Spring的两种代理方式:JDK动态代理和CGLIB动态代理

AOP的实现原理:     都是基于代理模式,都是生成一个大代理对象
                静态AOP:  AspectJ实现的AOP, 将切面代码直接编译到Java类文件中               ---    实现:  JDK提供的动态代理技术
                动态AOP:  将切面代码进行动态织入实现的AOP   ---  Spring的AOP为动态AOP       ---    实现:  CGLIB(动态字节码增强技术)

      JDK动态代理:  ---   InvocationHandler 和 Proxy.newProxyInstance()      --- 动态代理的基本原理为反射 + 多态 + 聚合

                           InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
                           Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象

                           JDK动态代理要求被代理者实现一个接口,只有接口中的方法才能被代理, 其方法是,将被代理对象注入到一个中间对象,而中间对象实现InvocationHandler接口,
                           在实现该接口时,可以在被代理对象调用它的方法时,在调用前后插入一些代码,
                           Proxy.newProxyInstance()能够利用中间对象来生产代理对象,插入的代码就是切面代码
                           局限:
                                 被代理的对象必须实现接口,而且只有接口中的方法才能被代理
                           ---   实例:com.jay.advanced.java.动态代理.demo1
                           eg:
                             public class MyProxyInvocationHandler implements InvocationHandler {
                                 private Object target;    // 被代理的对象

                                 public MyProxyInvocationHandler(Object target) {
                                     this.target = target;
                                 }

                                 public Object getTarget() {
                                     return target;
                                 }
                                 public void setTarget(Object target) {
                                     this.target = target;
                                 }

                                 /*
                                  * 动态代理,执行被代理的方法
                                  */
                                 @Override
                                 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                     // 在目标对象的方法执行之前简单的打印一下
                                     System.out.println("------------------before------------------");

                                     // 执行目标对象的方法
                                     Object result = method.invoke(target, args);

                                     // 在目标对象的方法执行之后简单的打印一下
                                     System.out.println("-------------------after------------------");

                                     return result;
                                 }

                                 /*
                                  * 获取代理对象
                                  */
                                 public Object getProxy(){
                                     return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
                                 }
                             }

                           测试:
                               public class Test {
                                   public static void main(String args[]){
                                       //实例化目标对象  --- 被代理对象
                                       Object proxyedObj = new UserServiceImpl();

                                       //实例化中间对象
                                       MyProxyInvocationHandler proxyInvocationHandler = new MyProxyInvocationHandler(proxyedObj);

                                       //根据目标对象  生成  代理对象, 对目标对象的接口进行代理::UserServiceImpl.class.getInterfaces()
                                       UserService proxyObj = (UserService) proxyInvocationHandler.getProxy();

                                       //调用代理对象的方法
                                       proxyObj.addUser(new User());
                                       proxyObj.getUser(1);
                                   }
                               }


      cglib动态代理:---   字节码生成技术      实现  MethodInterceptor接口,重写其 interceptor()方法
                           CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑

                           继承被代理对象,然后重写被代理的方法,在覆盖该方法时,插入自己的代码,
                           因为需要重写被代理对象的方法,要求:被代理的方法不能使final方法,因为final方法不能被覆盖
                          eg:
                            public class CglibProxy implements MethodInterceptor {

                                private Object target;    // 被代理对象

                                public CglibProxy(Object target){
                                    this.target = target;
                                }

                                @Override
                                public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
                                    System.out.println("do sth before....");
                                    Object result = proxy.invokeSuper(o, objects);
                                    System.out.println("do sth after....");
                                    return result;
                                }

                                public Object getProxyObject() {
                                    Enhancer enhancer = new Enhancer();
                                    enhancer.setSuperclass(this.target.getClass());    // 设置父类
                                    // 设置回调
                                    enhancer.setCallback(this);    // 在调用父类方法时,回调 this.intercept()
                                    // 创建代理对象
                                    return enhancer.create();
                                }
                            }

                          测试:
                              public class Test {
                                  public static void main(String[] args){
                                      Object proxyedObject = new UserServiceImpl();    // 被代理的对象
                                      CglibProxy cgProxy = new CglibProxy(proxyedObject);
                                      UserService proxyObject = (UserService) cgProxy.getProxyObject();
                                      proxyObject.getUser(1);
                                      proxyObject.addUser(new User());
                                  }
                              }
                   2种方式对比:
                              CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,
                              所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
                              同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理!

                              CGLib所创建的动态代理对象的性能比JDK所创建的代理对象性能高不少,大概10倍,但CGLib在创建代理对象时所花费的时间却比JDK动态代理多大概8倍,
                              所以对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建新的实例,所以比较适合CGLib动态代理技术,反之则适用于JDK动态代理技术。
                              另外,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行处理


                   默认情况下,Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的代理使用CGLIB来实现

 

 

Spring中的动态代理的使用

Spring定义了org.springframework.aop.framework.AopProxy接口,并提供了如下两种final类型的实现类:

 

关于Spring中选择代理类型的判断

如果通过ProxyFactory的setInterfaces(Class[] interfaces)指定针对接口进行代理,ProxyFactory就使用JdkDynamicAopProxy,如果是针对类的代理,则使用Cglib2AopProxy。另外,如果使用ProxyFactory的setOptimize(true)方法,则启动了优化代理方式,这样针对接口的代理也会使用Cglib2AopProxy。

在引介增强中就需要强制指定为Cglib2AopProxy,因为引介增强是一种比较特殊的增强类型,不是在目标周围织入增强,而是为目标类创建新的方法和属性,所以引介增强的连接点事类级别的。而非方法级别的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值