静态代理和动态代理
spring Aop编程中常会使用代理操作。
代理即 为某⼀个对象创建⼀个代理对象,程序不直接⽤原本的对象,⽽是由创建的代理对象来控制对原对象,通过代理类这中间⼀层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间。
而代理又分静态代理和动态代理。
静态代理
由程序创建或特定⼯具⾃动⽣成源代码,在程序运行前,代理类的.class⽂件就已经存在通过将⽬标类与代理类实现同⼀个接⼝,让代理类持有真实类对象,然后在代理类⽅法中调用真实类⽅法,在调⽤真实类方法的前后添加我们所需要的功能扩展代码来达到增强的⽬的。
优点:
代理使客户端不需要知道实现类是什么,怎么做的,⽽客户端只需知道代理即可
⽅便增加功能,拓展业务逻辑
缺点:
如果接⼝增加⼀个⽅法,除了所有实现类需要实现这个⽅法外,所有代理类也需要实现此⽅法。增加了代码维护的复杂度
代理类中出现⼤量冗余的代码,⾮常不利于扩展和维护
动态代理
在程序运⾏时,运⽤反射机制动态创建⽽成,⽆需⼿动编写代码JDK动态代理与静态代理⼀样,⽬标类需要实现⼀个代理接⼝,再通过代理对象调⽤⽬标⽅法
一般常见的动态代理有JDK和CGLib
JDK动态代理例子如下:
定义⼀个java.lang.reflect.InvocationHandler接⼝的实现类,重写invoke⽅法 //Object proxy:被代理的对象 //Method method:要调⽤的⽅法 //Object[] args:⽅法调⽤时所需要参数 public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
实现类 public class JdkProxy implements InvocationHandler { //⽬标类 private Object targetObject; //获取代理对象 public Object newProxyInstance(Object targetObject){ this. targetObject = targetObject; //绑定关系,也就是和具体的哪个实现类关联 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(),this);
}
@OVERRIDE public Object invoke(Object proxy, Method method, Object[] args) { Object result = null; try{ System.out.println("通过JDK动态代理调⽤ "+method.getName() +", 打印⽇志 begin"); result = method.invoke(targetObject,args); System.out.println("通过JDK动态代理调⽤ "+method.getName() +", 打印⽇志 end"); }catch (Exception e){ e.printStackTrace(); } return result; } }
两种动态代理的区别:
JDK动态代理:要求⽬标对象实现⼀个接⼝,但是有时候⽬标对象只是⼀个单独的对象,并没有实现任何的接⼝,这个时候就可以⽤CGLib动态代理
CGLib动态代理,它是在内存中构建⼀个⼦类对象从⽽实现对⽬标对象功能的扩展
JDK动态代理是⾃带的,CGlib需要引⼊第三⽅包
CGLib动态代理基于继承来实现代理,所以⽆法对final类、private⽅法和static⽅法实现代理
Spring AOP中的代理使⽤的默认策略:
如果⽬标对象实现了接⼝,则默认采⽤JDK动态代理
如果⽬标对象没有实现接⼝,则采⽤CgLib进⾏动态代理
如果⽬标对象实现了接扣,程序⾥⾯依旧可以指定使⽤CGlib动态代理