动态代理
代理类在程序运行时创建的代理方式被称为动态代理
静态代理中,代理类是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是运行时根据我们在Java代码中的指示动态生成的。相比较静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法,比如想要在每个代理方法前都加上一个处理方法,静态代理就需要在每个类内部加上这个方法
静态代理与动态代理的区别
静态代理
优点
简单、效率高、容易理解
缺点
当目标类增多,代理类也需要增加
当接口方法增加或修改的时候,很多类都需要修改,因为目标类和代理类都实现了相同的接口
动态代理
优点
动态代理中的目标类很多的时候代理类的数量可以很少
修改接口的方法的时候不会影响到代理类
代理类可以自动帮助我们生成无需手动
JDK动态代理
JDK动态代理是基于反射机制,生成一个实现代理接口的匿名类,然后重写方法进行方法增强。在调用具体方法前通过调用InvokeHandler的invoke方法来处理。
他的特点是生成代理类的速度很快,但是运行时调用方法操作会比较慢,因为是基于反射机制的,而且只能针对接口编程,即目标对象要实现接口
public interface Person { void sayHi(); }
public class Student implements Person{ @Override public void sayHi() { System.out.println("Hi 我是一名学生"); } }
public class JDKProxy implements InvocationHandler { Object target; public Object newProxy(Object obj){ this.target = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("你好"); Object invoke = method.invoke(target, args); System.out.println("再见"); return invoke; } }
public class JDKTest { public static void main(String[] args) { Person proxy = (Person) new JDKProxy().newProxy(new Student()); proxy.sayHi(); } }
CGLIB动态代理
Cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库,它是开源的。动态代理是利用 asm 开源包,将目标对象类的 class 文件加载进来,然后修改其字节码生成新的子类来进行扩展处理
<--引入依赖--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
public class Student { public void sayHi(){ System.out.println("Hi 我是一名学生"); } }
public class CglibProxy implements MethodInterceptor { private Object target; public Object newProxy(Object target){ this.target = target; // 增强器 Enhancer enhancer = new Enhancer(); enhancer.setCallback(this); enhancer.setSuperclass(target.getClass()); return enhancer.create(); } /** * * @param o 生成代理类的实例 * @param method 上文实体类所调用的被代理的方法引用 * @param objects 方法列表参数 * @param methodProxy 生成代理类对方法的引用 * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("你好"); Object invoke = methodProxy.invoke(target, objects); System.out.println("再见"); return invoke; } }
public class CglibTest { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Student student = (Student) proxy.newProxy(new Student()); student.sayHi(); } }
两种代理方式的区别
JDK动态代理是基于反射机制,生成一个实现了接口继承了proxy类的匿名类而Cglib动态代理是基于继承机制,继承被代理类,底层是基于asm第三方框架对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理
JDK动态代理生成类的速度快,后续执行类的方法操作慢而Cglib代理是生成类的速度慢,后续执行类的方法操作快
为什么JDK生成快,执行慢而Cglib与之相反
JDK动态代理通过会拦截方法,通过反射获取模板接口名字、内部方法以及参数,拼接生成一个新的Java代理对象
生成的代理对象不能直接调用被代理对象的方法,而是通过反射所有每次都得用反射调用一次所以执行方法都需要通过反射
Cglib代理实际上通过继承,生成一个子类,就是将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理,生成类的速度慢但是后续执行时候就很快