设计模式之代理模式-动态代理

概念

  • 动态产生代理,实现对不同类,不同方法的代理
  • 动态代理实现可采用:JDK动态代理和cglib产生代理(spring采用cglib继承方式实现动态代理)

JDK动态代理

设计模式之代理模式-动态代理_第1张图片
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

  • Interface InvocationHandler:该接口仅定义了一个方法
      public Object invoke(Object proxy, Method method, Object[] args)
    proxy:代理类
    method:被代理的方法
    args:该方法的参数数组

  • Proxy:该类即为动态代理类
      public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类在接口中声明过的方法)

  • 所谓Dynamic Proxy是在运行时生成的class,该class需要实现一组interface,使用jdk动态代理类时,必须要实现InvocationHandler接口

  • 只能代理实现了接口的类

  • 没有实现接口的类不能实现JDK的动态代理

cglib动态代理

cglib包介绍

 代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。

 CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)。EasyMock和jMock是通过使用模仿(mock)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(mock)对象。

 CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

cglib代码包结构

设计模式之代理模式-动态代理_第2张图片

  • core (核心代码)

    EmitUtils

    ReflectUtils

    KeyFactory

    ClassEmitter/CodeEmitter

    NamingPolicy/DefaultNamingPolicy

    GeneratorStrategy/DefaultGeneratorStrategy

    DebuggingClassWriter

    ClassGenerator/AbstractClassGenerator

  • beans (bean操作类)

    BeanCopier

    BulkBean

    BeanMap

    ImmutableBean

    BeanGenerator

  • reflect

    FastClass

  • proxy

    MethodInterceptor , Dispatcher, LazyLoader , ProxyRefDispatcher , NoOp , FixedValue , InvocationHandler(提供和jdk proxy的功能)

    Enhancer

    CallbackGenerator

    Callback

    CallbackFilter

  • util

    StringSwitcher

    ParallelSorter

  • transform

代码实现

业务需求

  业务要求对已有的http api请求的接口:实现对请求的url和请求结果记录日志

  • HttpApi 接口定义
    package cn.tswine.dp.proxy;
    
    /**
     * @Author: silly
     * @Date: 2020/1/31 20:44
     * @Version 1.0
     * @Desc
     */
    public interface HttpApi {
           
        String request(String url);
    }
    
  • RealHttpApi业务实现类
    public class RealHttpApi implements HttpApi {
           
       @Override
       public String request(String url) {
           
           try {
           
               //模拟请求的时间
               Thread.sleep(new Random().nextInt(1000));
           } catch (InterruptedException e) {
           
               e.printStackTrace();
           }
           //模式返回结果
           return "success";
       }
    }
    

JDK动态代理实现

  • 实现步骤
    1.创建一个实现接口InvocationHandler 的类,必须实现invoke方法
    2.创建被代理的类以及接口
    3.调用Proxy的静态方法,创建一个代理类newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
    4.通过代理调用方法
  • LogInvocationHandler
    /**
     * 实现打印日志事务
     */
    public class LogInvocationHandler implements InvocationHandler {
           
    
        private Object target;
    
        public LogInvocationHandler(Object target) {
           
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           
            System.out.println("request params:" + (args == null ? "" : Arrays.toString(args)));
            Object invoke = method.invoke(target, args);
            System.out.println("response :" + (invoke == null ? "NULL" : invoke.toString()));
            return invoke;
        }
    }
    
  • Client
    /**
     * 客户端
     */
    public class Client {
           
    
        public static void main(String[] args) {
           
            String url = "https://www.csdn.net";
            RealHttpApi realHttpApi = new RealHttpApi();
            InvocationHandler invocationHandler = new LogInvocationHandler(realHttpApi);
            HttpApi httpApiProxy  = (HttpApi) Proxy.newProxyInstance(realHttpApi.getClass().getClassLoader(), realHttpApi.getClass().getInterfaces(), invocationHandler);
            httpApiProxy.request(url);
        }
    }
    

cglib动态代理实现

  • 引入cglib包
    <dependency>
    	<groupId>cglib</groupId>
    	<artifactId>cglib</artifactId>
      	<version>3.3.0</version>
    </dependency>
    
  • CglibProxy
    /**
     * cglib代理类
    */	
    public class CglibProxy implements MethodInterceptor {
           
    
    	private Enhancer enhancer = new Enhancer();
    
      /**
    	 * 获取代理类
    	 *
     	* @param clazz
      * @return
     	*/
    	public Object getProxy(Class clazz) {
           
      	  //设置创建子类的类
        	enhancer.setSuperclass(clazz);
      	  enhancer.setCallback(this);
       	 //创建子类的实例
       	 return enhancer.create();
     }
    
        /**
         * 拦截所有目标类方法的调用
         *
         * @param obj         目标类的实例
         * @param method      目标方法的反射对象
         * @param args        方法的参数
         * @param methodProxy 代理类的实例方法
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
           
            System.out.println("request params:" + (args == null ? "" : Arrays.toString(args)));
            //代理类调用父类的方法
            Object invoke = methodProxy.invokeSuper(obj, args);
            System.out.println("response :" + (invoke == null ? "NULL" : invoke.toString()));
            return invoke;
        }
    }
    

你可能感兴趣的:(设计模式)