java动态代理详解(一)
2016-10-11 15:22
344 查看
(一).什么是动态代理?
定义:动态代理为其他对象提供一种代理以控制对这个对象的访问。
(二).为什么要用动态代理?
动态代理的优势就是实现无侵入式的代码扩展,比如 Spring的AOP的拦截功能是由java中的动态代理来实现的。
动态代理可以用在记录方法的日志,AOP,权限等等,而不侵入原来类的代码。
(三).java中动态代理的实现
在java中如果要为一个类创建动态代理,这个类必须实现接口,然后还有两个重要的东西:Proxy和InvocationHandler。Proxy类是创建动态代理的主要类。它的newProxyInstance()静态方法返回一个代理对象的实例,而InvocationHandler是该被代理类的事物处理器。具体看代码。
1.创建一个的接口,并创建该接口的实现类,
2.通过实现InvocationHandler接口创建自己的调用处理器
3.写测试类,并为对象创建代理对象
输出结果:
true
userServiceProxy的Class类是:class $Proxy0
userServiceProxy中的属性有:m3, m1, m0, m2,
userServiceProxy中的方法有:addUser, hashCode, equals, toString,
userServiceProxy的父类是:class java.lang.reflect.Proxy
userServiceProxy实现的接口是:com.my.proxyTest.UserService,
运行结果为:
开始添加用户。。。
增加的用户名为:张三。可以发现在没有改动原来类的基础上,增加了原来类的业务逻辑。这就是java动态代理运用。
(四)分析源码
先看看Proxy类的主要代码
Proxy构造方法
Proxy静态方法newProxyInstance
类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据:
我们可以import sun.misc.ProxyGenerator,调用 generateProxyClass方法产生binary data,然后写入文件,最后通过反编译工具来查看内部实现原理。 反编译后的userServiceProxy.java Proxy静态方法newProxyInstance
一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
生成的ProxySubject继承Proxy类实现UserServiceImpl接口,实现的UserServiceImpl的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))
java的用jdk实现动态代理有个美中不足,它只能实现继承接口的类。对于那些没有实现任何接口类无法使用动态代理,这时候就需要用到第三方的cglib来实现。
定义:动态代理为其他对象提供一种代理以控制对这个对象的访问。
(二).为什么要用动态代理?
动态代理的优势就是实现无侵入式的代码扩展,比如 Spring的AOP的拦截功能是由java中的动态代理来实现的。
动态代理可以用在记录方法的日志,AOP,权限等等,而不侵入原来类的代码。
(三).java中动态代理的实现
在java中如果要为一个类创建动态代理,这个类必须实现接口,然后还有两个重要的东西:Proxy和InvocationHandler。Proxy类是创建动态代理的主要类。它的newProxyInstance()静态方法返回一个代理对象的实例,而InvocationHandler是该被代理类的事物处理器。具体看代码。
1.创建一个的接口,并创建该接口的实现类,
package com.my.proxyTest; //创建一个接口 public interface UserService { public void addUser(String userName); }
package com.my.proxyTest; public class UserServiceImpl implements UserService { @Override public void addUser(String userName) { System.out.println("增加的用户名为:"+userName); } }
2.通过实现InvocationHandler接口创建自己的调用处理器
package com.my.proxyTest; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class UserServiceHandler implements InvocationHandler{ public Object target;//用Object接收,可以传进来任意类型的对象。 public UserServiceHandler(Object obj){ target=obj; } /** * proxy:代理类 * method:被代理类的方法 * args:该方法的参数数组 */ @Override //这里的invoke方法不是显示调用,而是java创建的代理对象$Proxy0.class调用 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始添加用户。。。");//在原来的对象方法执行前面,执行这段代码 Object obj=method.invoke(target,args);//传入被代理对象,也就是目标对象 return obj; } }
3.写测试类,并为对象创建代理对象
package com.my.proxyTest; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { UserService userService=new UserServiceImpl(); UserServiceHandler h=new UserServiceHandler(userService); //把$Proxy0强制转换成UserService UserService userServiceProxy=(UserService)Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), h); System.out.println(userServiceProxy instanceof Proxy); //输出为true //输出:userServiceProxy的Class类是:class $Proxy0 //这里可以看出userServiceProxy的Class类是$Proxy0。 //这个$Proxy0类继承了Proxy,实现了UserServiceImpl接口 System.out.println("userServiceProxy的Class类是:"+userServiceProxy.getClass().toString()); System.out.print("<span style="font-size: 14px;">userServiceProxy</span>中的属性有:"); Field[] field=userServiceProxy.getClass().getDeclaredFields(); for(Field f:field){ System.out.print(f.getName()+", "); } System.out.print("\n"+"<span style="font-family: Arial, Helvetica, sans-serif;">userServiceProxy</span>中的方法有:"); Method[] method=userServiceProxy.getClass().getDeclaredMethods(); for(Method m:method){ System.out.print(m.getName()+", "); } System.out.println("\n"+"<span style="font-family: Arial, Helvetica, sans-serif;">userServiceProxy</span><span style="font-family: Arial, Helvetica, sans-serif;">的父类是:"+userServiceProxy.getClass().getSuperclass()); </span> System.out.print("\n"+"<span style="font-family: Arial, Helvetica, sans-serif;">userServiceProxy</span>实现的接口是:"); Class<?>[] interfaces=userServiceProxy.getClass().getInterfaces(); for(Class<?> i:interfaces){ System.out.print(i.getName()+", "); } System.out.println("\n\n"+"运行结果为:"); userServiceProxy.addUser("张三"); } }
输出结果:
true
userServiceProxy的Class类是:class $Proxy0
userServiceProxy中的属性有:m3, m1, m0, m2,
userServiceProxy中的方法有:addUser, hashCode, equals, toString,
userServiceProxy的父类是:class java.lang.reflect.Proxy
userServiceProxy实现的接口是:com.my.proxyTest.UserService,
运行结果为:
开始添加用户。。。
增加的用户名为:张三。可以发现在没有改动原来类的基础上,增加了原来类的业务逻辑。这就是java动态代理运用。
(四)分析源码
先看看Proxy类的主要代码
Proxy构造方法
private final static Class[] constructorParams ={ InvocationHandler.class }; //定义参数是<span style="font-family: Arial, Helvetica, sans-serif;">InvocationHandler的数组</span> protected InvocationHandler h; // 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用 private Proxy() { } // 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用 protected Proxy(InvocationHandler h) { this.h = h; }
Proxy静态方法newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException { // 检查 h 不为空,否则抛异常 if (h == null) { throw new NullPointerException(); } // 获得与指定类装载器和一组接口相关的代理类类型对象 Class cl = getProxyClass(loader, interfaces); // 通过反射获取构造函数对象并生成代理类实例 try { Constructor cons = cl.getConstructor(constructorParams); //cons即是形参为InvocationHandler类型的构造方法,通过构造方法创建代理类实例, //此时需将调用处理器对象作为参数被传入 return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } }
类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据:
public static byte[] generateProxyClass(final String name, Class[] interfaces)
我们可以import sun.misc.ProxyGenerator,调用 generateProxyClass方法产生binary data,然后写入文件,最后通过反编译工具来查看内部实现原理。 反编译后的userServiceProxy.java Proxy静态方法newProxyInstance
public final class $Proxy0 extends Proxy implements Subject { private static Method m1; private static Method m0; private static Method m3; private static Method m2; static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("***.RealSubject").getMethod("request", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } //static public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } @Override public final boolean equals(Object obj) { try { return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue(); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @Override public final int hashCode() { try { return ((Integer) super.h.invoke(this, m0, null)).intValue(); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final void request() { try { super.h.invoke(this, m3, null); return; } catch (Error e) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @Override public final String toString() { try { return (String) super.h.invoke(this, m2, null); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }
总结
一个典型的动态代理创建对象过程可分为以下四个步骤:1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
生成的ProxySubject继承Proxy类实现UserServiceImpl接口,实现的UserServiceImpl的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))
java的用jdk实现动态代理有个美中不足,它只能实现继承接口的类。对于那些没有实现任何接口类无法使用动态代理,这时候就需要用到第三方的cglib来实现。
相关文章推荐
- Java动态代理机制详解-转自ITEYE论坛
- java jdk动态代理详解
- java的动态代理机制详解
- Java静态代理以及动态代理使用详解
- java 动态代理原理详解
- java的动态代理机制详解
- java的动态代理机制详解
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- JAVA动态代理详解
- Java动态代理详解
- java的动态代理机制详解
- java动态代理详解
- Java的动态代理机制详解
- Java动态代理的实现详解
- 黑马程序员—Java动态代理详解
- 详解java动态代理
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- java的动态代理机制详解
- java的动态代理机制详解
- java动态代理详解