AOP-JDK动态代理和Cglib动态代理
静态代理:
-
由程序员自己创建代理类,在程序运行之前代理类的.class文件就已经生成了
-
静态代理事先就知道要代理的是什么
-
代理类持有被代理类对象的引用
-
调用时,代理对象调用被调用代理对象的响应方法,可以在其前后额外的添加其他功能
动态代理:
- 动态代理是在程序运行期间,通过反射机制动态的创建而成的
- 动态代理事先不知道要代理的目标,只有在运行的时候才知道
代理模式与AOP的关系:
- AOP采用代理模式来实现
- 我们编写的业务对象就是被代理的对象,代理对象是在程序运行的时候由spring容器动态生成的
- 当使用AOP的时候:
- spring容器将目标对象拦截下来(已经持有对目标对象的引用了),为其加入通知的一些功能,再调用目标对象的原有方法.
- 将生成的代理类放到spring容器中
- 当我们要获取目标对象的bean的时候,实际上是获取的代理对象的bean
- 在进行调用的时候,首先执行的是代理类的代码,再由代理类调用目标类的方法进行输出
静态代理举例:
-
这里举一个租房的例子:代理类( 房产中介 ) , 被代理类( 房子主人 ) , 调用者( 租客 ),中介和房子主人通过房子联系在一起,所以我们先来一个房子的接口,然后这个房子有被出租的功能
/** *中介与房子主人的关联点 */ public interface House { void letHouse(double money); }
一个中介类:
/** * 代理类 */ public class HouseProxy implements House{ // 持有被代理类的引用 private HouseMaster houseMaster; public HouseProxy(HouseMaster houseMaster) { this.houseMaster = houseMaster; } @Override public void letHouse(double money) { System.out.println("中介=>收到租客租房请求,租金收到:"+money); double newMoney=money-500; houseMaster.letHouse(newMoney); System.out.println("中介=>吃掉"+(money-newMoney)+"的代理费,感谢老板"); } }
一个房子主人类:
public class HouseMaster implements House{ @Override public void letHouse(double money) { System.out.println("房子主人=>收到租金:"+money); } }
租客类:
/** * 客户类,租客 */ public class Customer { public static void main(String[] args) { HouseMaster houseMaster = new HouseMaster(); HouseProxy houseProxy = new HouseProxy(houseMaster); houseProxy.letHouse(2000.00); } }
运行结果:
中介=>收到租客租房请求,租金收到:2000.0 房子主人=>收到租金:1500.0 中介=>吃掉500.0的代理费,感谢老板
由此可以看出,代理类给被代理类添加了一些功能,房子租金他涨价了500.
JDk动态代理
-
目标类:实现了一个接口User,我们给这个类添加一个统计性能的功能
/** * 目标类 */ public class UserImpl implements User { @Override public void addUser() { for (int i=0;i<1000;i++){ System.out.print(","+i); } System.out.println(); } }
要给目标类添加的功能:
/** * 给目标类对象添加功能 */ public class MonitorHandler implements InvocationHandler { //持有目标类的引用 private Object target; public MonitorHandler(Object target) { this.target = target; } /** * @param o * @param method 目标类的方法 * @param args 目标类方法的参数 * @return * @throws Throwable */ @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { // 统计目标类方法执行之前的时间 long beforerTime=System.currentTimeMillis(); // 执行目标类方法 Object invoke = method.invoke(target, args); // 统计目标类方法执行之后的时间 long afterTime=System.currentTimeMillis(); System.out.println("方法"+method.getName()+"总共执行了"+(afterTime-beforerTime)+"毫秒"); //返回目标类对象 return invoke; } }
返回代理对象:
/** * 生成代理类 */ public class JdkProxy{ public static Object createProxy(Object target){ // 获得目标类的类加载器 ClassLoader classLoader = target.getClass().getClassLoader(); // 获得目标类的接口 Class<?>[] interfaces = target.getClass().getInterfaces(); // 给目标类添加功能 MonitorHandler monitorHandler = new MonitorHandler(target); // 调用Proxy的newProxyInstance()方法获得一个代理对象 Object proxyTarget = Proxy.newProxyInstance(classLoader, interfaces, monitorHandler); return proxyTarget; } }
执行结果:
,0,1,2,3,4,5,6,....... 方法addUser总共执行了16毫秒
Cglib动态代理:
-
如果目标类没有实现接口呢?那么就会spring就会使用Cglib来生成动态代理.
-
目标类:还是添加一个统计方法性能的功能
/** * 目标类,没有实现接口 */ public class UserImpl{ public void addUser() { for (int i=0;i<1000;i++){ System.out.print(","+i); } System.out.println(); } }
要添加的功能:
/** * 方法拦截器,给目标类添加功能,注意要导cglib的包,不要导错了 */ public class MethodMonitor implements MethodInterceptor { @Override public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //前置处理 long before=System.currentTimeMillis(); //调用父类相应的方法 Object result = methodProxy.invokeSuper(target, args); //后置处理 long after=System.currentTimeMillis(); System.out.println("方法:"+method.getName()+"执行了:"+(after-before)+"毫秒"); return result; } }
生成Cglib动态代理对象:
/** * 返回代理类对象 */ public class CglibProxy { public static Object createCglibProxy(Object target){ // 创建增强器 Enhancer enhancer = new Enhancer(); // 将目标类设置成父类 enhancer.setSuperclass(target.getClass()); // 设置方法拦截器 enhancer.setCallback(new MethodMonitor()); // 创建代理类对象 Object cglibProxy = enhancer.create(); return cglibProxy; } }
测试类:
public class CglibApp { public static void main(String[] args) { UserImpl user = new UserImpl(); UserImpl cglibProxy = (UserImpl)CglibProxy.createCglibProxy(user); cglibProxy.addUser(); } }
结果:
,0,1,2,3,4,5,6,7,8,9.... 方法:addUser执行了:36毫秒
JDK动态代理与Cglib动态代理的区别:
- JDK使用接口的方式实现动态代理
- Cglib使用继承的方式实现动态代理
- 性能:jdk1.8之前cglib动态代理性能更好,从执行时间上来看,jdk1.8之后jdk动态代理胜出.
- spring默认是使用jdk动态代理生成代理类的,但是也支持cglic