设计模式(一) 动态代理初尝试


  • 摘要
      之前老是听说动态代理,一直没有机会好好看过,现在就把动态代理的实现逻辑和用处整理一下。
    首先提两个概念,委托类和代理类。委托类就是实际业务逻辑的处理者,代理类是处于请求发起者与委托类之间的角色,所有对委托类的请求都会经过代理类。
    就是委托类将请求处理委托给代理类,代理类可以起到方法拦截、功能增强的作用。
    实现动态代理的方式有很多,现在主流的主要jdk和cglib这两个。下面就用示例代码说明下动态代理的过程,以及用动态代理实现拦截器。
  • 用JDK实现动态代理
      jdk实现动态代理的包是java.lang.reflect.*,jdk实现动态代理有限制,委托类必须要实现接口,所以先要创建一个接口
    public interface MyInterface {
    
        //jdk
        public void tes1();
    
        //cglib
        public void test2(String val);
    
    }


    创建接口实现类

    public class MyTarget implements MyInterface {
    
        //jdk
        @Override
        public void tes1() {
            System.out.println("委托类业务处理!");
        }
    
        //cglib
        @Override
        public void test2(String val) {
            System.out.println("业务处理结果:"+val);
        }
    }


    动态代理逻辑代码

    package proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class MyProxyTest implements InvocationHandler {  //继承InvocationHandler,拦截方法
    
        private Object target=null;
    
        //构造函数
        public MyProxyTest(Object target){
            this.target = target ;
        }
    
        //获取代理类的方法
        public static Object getProxy(Object target){
            //通过proxy创建代理类,需要三个参数,委托类的类加载器、委托类实现的接口、代理类
            /**
             * 这是jdk的动态代理模式,必须要有接口
             * proxy会把代理类挂载到所有接口下面
             * 如果委托类没有实现任何接口会有问题,改用CGLIB的enhancer增强类做动态代理
             */
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),new MyProxyTest(target));
        }
    
        //拦截方法
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("进入代理逻辑!");
            System.out.println("代理类处理逻辑!");
            Object result=null;
            result = method.invoke(target,args);
            System.out.println("委托类处理完后的逻辑!");
            return result;
        }
    }

      getProxy方法就是绑定委托类和代理类之间关系的方法,这里绑定的代理类是this当前对象,也就是MyProxyTest 的实例对象,由于实现了InvocationHandler接口,所以在方法调用之前都会
    通过invoke方法,在这里就可以写功能增强的代码。method.invoke(target,args)是通过反射运行委托类的方法。

    测试用例

    public class JunitTest {
        public static void main(String[] args) {
            /**
             * jdk动态代理
             */
            System.out.println("---------jdk动态代理--------");
            //委托类
            MyTarget target = new MyTarget();
            //给委托类绑定代理类
            MyInterface proxy = (MyInterface)MyProxyTest.getProxy(target);
            proxy.tes1();
        }
    }


    运行结果

    ---------jdk动态代理--------
    进入代理逻辑!
    代理类处理逻辑!
    委托类业务处理!
    委托类处理完后的逻辑!

    我们发现进入了代理类的处理逻辑。



  • CGLIB实现动态代理
      CGLIB实现动态代理和JDK大同小异,不过CGLIB是通过创建增强类Enhancer,并且设置Enhancer的委托类和代理类来实现动态代理。CGLIB的委托类不需要实现接口。
    动态代理逻辑
    package proxy;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class MyCgLibProxy implements MethodInterceptor {
    
        public Object getProxy(Class target){
            //创建增强类
            Enhancer enhancer = new Enhancer();
            //设置委托类
            enhancer.setSuperclass(target);
            //设置代理类
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
    
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("进入代理逻辑!");
            System.out.println("代理类处理逻辑!");
            Object result=null;
            result = methodProxy.invokeSuper(o,objects);
            System.out.println("委托类处理完后的逻辑!");
            return result;
        }
    }

    这里的getProxy接收的不是委托类的实例对象而是委托类。代理类是this,MyCgLibProxy 的实例对象,由于实现了MethodInterceptor拦截器,所以方法调用都会经过intercept。

    测试用例

    package proxy;
    
    public class JunitTest {
        public static void main(String[] args) {
            /**
             * cglib动态代理
             */
            System.out.println("---------cglib动态代理--------");
            MyCgLibProxy cgLib = new MyCgLibProxy();
            MyInterface cgLibProxy = (MyInterface)cgLib.getProxy(MyTarget.class);
            cgLibProxy.test2("cglib动态代理");
        }
    }

    运行结果

    ---------cglib动态代理--------
    进入代理逻辑!
    代理类处理逻辑!
    业务处理结果:cglib动态代理
    委托类处理完后的逻辑!

    简单的实现动态代理的两种方式就完成了,之后再讲解拦截器和责任链模式