1 jdk动态代理
1.1 什么是代理
代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式。为了对外开放协议,B往往实现了一个接口,A也会去实现接口。但是B是“真正”实现类,A则比较“虚”,他借用了B的方法去实现接口的方法。A虽然是“伪军”,但它可以增强B,在调用B的方法前后都做些其他的事情。Spring AOP就是使用了动态代理完成了代码的动态“织入”。
解答2 为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
1.2 使用代理的好处
使用代理好处还不止这些,一个工程如果依赖另一个工程给的接口,但是另一个工程的接口不稳定,经常变更协议,就可以使用一个代理,接口变更时,只需要修改代理,不需要一一修改业务代码。从这个意义上说,所有调外界的接口,我们都可以这么做,不让外界的代码对我们的代码有侵入,这叫防御式编程。代理其他的应用可能还有很多。
1.3代理的分类
上述例子中,类A写死持有B,就是B的静态代理。如果A代理的对象是不确定的,就是动态代理。动态代理目前有两种常见的实现,jdk动态代理和cglib动态代理。
1.4 什么是jdk动态代理
动态代理是在程序运行时通过反射机制操作字节码,从而动态的创建 字节码文件,进而创建代理对象。
1.5 jdk动态代理的实现
动态代理中有一些坑,比如说:
- JDK的动态代理要求被代理类必须实现接口,返回的代理对象也是该接口的实现类;如果想不实现接口,可以使用cglib
- 在实现InvocationHandler接口,重写
incvoke()
方法时,要注意method.invoke()
的第一个参数要传被代理对象,不能传重写的invoke()
方法的第一个参数,因为那个参数是代理对象。
jdk动态代理是代理的一种实现方式 只能代理接口
步骤
1 新建一个接口
2 新建一个实现类实现接口
3 新建一个代理类 实现java.lang.reflect.InvocationHandler接口
4 测试
1
package com.example; public interface Subject { public void doSomeThing(); }
2
package com.example; public class SubjectImpl implements Subject { @Override public void doSomeThing() { System.out.println("I do someThing"); } }
3
package com.example; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* jdk动态代理 */ public class JDKDynamicProxy implements InvocationHandler { private Object target; public JDKDynamicProxy(Object target) { this.target = target; } /* 获取被代理接口实例对象 */ public <T> T getProxy(){ return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("do somethig before"); Object result = method.invoke(target,args); System.out.println("dosomething after"); return result; } }
4
package com.example; public class TestJdkProxy { public static void main(String[] args) { // 保存生成的代理类的字节码文件 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); Subject subject = new JDKDynamicProxy(new SubjectImpl()).getProxy(); subject.doSomeThing(); } }
5 测试结果
do somethig before
I do someThing
dosomething after
2 jdk动态代理的原理
涉及的主要类
com.lang.reflect.Proxy
com.lang.reflect.InvocationHandler
java.lang.reflect.WeakCache
sun.misc.ProxyGenerator
JDK代理是不需要第三方库支持,只需要JDK环境就可以进行代理,使用条件:
1)实现InvocationHandler
2)使用Proxy.newProxyInstance产生代理对象
3)被代理的对象必须要实现接口
2 cglib动态代理
区别:jdk动态代理利用拦截器InvocationHandler 加上反射机制生成一个匿名代理类 在调用具体方法之前调用InvokeHandler处理
Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理