• spring AOP的两种代理


    本篇记录下spring AOP的两种代理,为下一篇AOP实现做下铺垫。

    1.JDK动态代理  2.cglib代理

    1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
    3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

    :JDK动态代理要比cglib代理执行速度快,但性能不如cglib好。所以在选择用哪种代理还是要看具体情况,一般单例模式用cglib比较好,具体原因请自行百度。

    一。JDK动态代理实现(原理是使用反射机制)

    首先定义接口,并实现

          public interface TestService{

               public int add();   
          }

          public class TestServiceImpl implements TestService{

             @Override
             public int add() {
                System.out.println("开始执行add...");
                return 0;
             }
         }

    定义代理类,这里要注意导入的包是import java.lang.reflect.*

       public class JDKDynamicProxy implements InvocationHandler {

         //被代理的目标对象
        private Object proxyObj;  
       
        /**
          * Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
          * loader    :类加载器 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
          * interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
           * h         :一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
         */
           public Object newProxy(Object proxyObj){  
                 this.proxyObj = proxyObj;
                //返回一个代理对象  
               return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(),   
                                          proxyObj.getClass().getInterfaces(),   
                                          this);  
           }  

          /**
           * 执行目标对象
           * Object  proxy:被代理的对象
           * Method  method:要调用的方法
           * Object  args[]:方法调用时所需要的参数
           */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                                       throws Throwable {      
                 before();
                 Object object = method.invoke(this.proxyObj,args);  // 通过反射机制调用目标对象的方法
                 after();      
                 return object;  
             }
        
             public void before(){
                  System.out.println("开始执行目标对象之前...");
             }
        
             public void after(){
                 System.out.println("开始执行目标对象之后...");
             }
         }

    测试类:

          public static void main(String[] args) {
            
              //我们要代理的真实对象
              TestService testService = new TestServiceImpl();       
              //testJDKProxyService.add();//不是用代理   
            
             JDKDynamicProxy JDKDynamicProxyTarget = new JDKDynamicProxy();
             TestService testServiceProxy = (TestService) JDKDynamicProxyTarget.newProxy(testService);
             //执行代理类的方法  
             testServiceProxy.add();

         }

    控制台显示

       

    二。CGLIB代理,需要导入 cglib-nodep-2.1_3.jar

        先说下cglib,CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

    先定义一个实现类(注意并没有实现接口)

      public class TestCGLIBServiceImpl {

        public int add() {
            System.out.println("开始执行add...");
            return 0;
        }
     }

    定义cglib代理类,此时导入的包应该是import net.sf.cglib.proxy.*

      import java.lang.reflect.Method;
      import net.sf.cglib.proxy.Enhancer;
      import net.sf.cglib.proxy.MethodInterceptor;
      import net.sf.cglib.proxy.MethodProxy;

        public class CGLIBProxy implements MethodInterceptor{

        private Object targetObject ;//被代理的目标对象
        
        public Object createProxyInstance(Object targetObject) {

               this . targetObject = targetObject;

               Enhancer enhancer = new Enhancer();

               enhancer.setSuperclass(targetObject.getClass());// 设置代理目标

               enhancer.setCallback( this );// 设置回调

               return enhancer.create();

        }
        

        /**
         * 在代理实例上处理方法调用并返回结果
         * @param object : 代理类
         * @param method :被代理的方法
         * @param args :该方法的参数数组
         * @param methodProxy
         */
        @Override
        public Object intercept(Object object, Method method, Object[] args,
                MethodProxy methodproxy) throws Throwable {       
            Object result = null;    
            try {
                  System. out .println( "前置处理开始 ..." );
                  result = methodproxy.invoke( targetObject , args);//执行目标对象的方法
                  System. out .println( "后置处理开始  ..." );
               } catch (Exception e) {
                   System. out .println( " 异常处理 ..." );
               } finally {
                   System. out .println( " 调用结束 ..." );
               }
               return result;
           }  
       }
    测试类:

       public class TestCGLIBProxy {

            public static void main(String[] args) {
            
              //我们要代理的真实对象
              TestCGLIBServiceImpl testCGLIB = new TestCGLIBServiceImpl();
               CGLIBProxy CGLIBproxy = new CGLIBProxy();
               TestCGLIBServiceImpl testCGLIBProxy = (TestCGLIBServiceImpl) CGLIBproxy.createProxyInstance(testCGLIB);
               testCGLIBProxy.add();
           }
       }

    结果图:

      

    写在后面:spring AOP的两种代理实现代码就写到这,这里只是实现了,如果你要想真正明白,还得熟悉其中原理机制,比如反射机制,newProxyInstance(...),Enhancer()原理,invoke()原理等等。

    下一篇将要记录spring AOP的基于注解的具体实现,而对于XML的我姑且不是用了,因为不够灵活,不够强大,要是有时间还会介绍下spring AOP 自定义注解的实现

  • 相关阅读:
    迈向架构设计师之路系列—简单对象访问模式(一)
    C#温故而知新学习系列之.NET运行机制—.NET中托管代码是指什么?(三)
    C#温故而知新学习系列之面向对象编程—静态方法(九)
    Android深入浅出系列之Android开发环境搭建—JDK(一)
    C#温故而知新学习系列之面向对象编程—自动属性(十一)
    C#温故而知新学习系列之面向对象编程—方法的重载(八)
    C#温故而知新学习系列之面向对象编程—分布类是什么?(十四)
    C#温故而知新学习系列之面向对象编程—属性(十二)
    C#温故而知新学习系列之面向对象编程—构造函数(七)
    C#温故而知新学习系列之.NET运行机制—.NET Framework概述及其组成(一)
  • 原文地址:https://www.cnblogs.com/jianjianyang/p/4904353.html
Copyright © 2020-2023  润新知