当前位置:主页 > 查看内容

深入理解动态代理模式下的编程思想——JDK动态代理源码的底层实

发布时间:2021-07-04 00:00| 位朋友查看

简介:最近笔者在深入了解一些开源框架比如Springmybatis这些框架去阅读源码学习作者的一些好的设计思路和写法。通过阅读源码你会学到很多大神的编程思想其中有很多很好的设计模式。看过很多源码的话你会发现很多地方都采用了代理设计模式来使得框架的灵活性开发今……

最近笔者在深入了解一些开源框架,比如Spring,mybatis这些框架,去阅读源码学习作者的一些好的设计思路和写法。通过阅读源码你会学到很多大神的编程思想,其中有很多很好的设计模式。看过很多源码的话,你会发现很多地方都采用了代理设计模式来使得框架的灵活性开发,今天主要根据JDK的动态代理来介绍下这个代理模式。

首先做个小的铺垫,很多描述代理模式的时候会用两个名词 代理对象 和 目标对象。
代理对象代理的就是目标对象。这俩的关系在程序里不是恒定的。
就比如 一种恋爱关系 A->B->C A暗恋B B是被暗恋的, 但是B暗恋C 相对有C来说C是被暗恋的,就是大家清楚这种关系 是相对的,不是绝对的。


代理模式分为动态代理和静态代理;

静态代理

静态代理的体现在 继承和聚合-接口的形式

继承形式实现静态代理

/**
 * 定义一个基础类
 */
public class BaseMapper {
	//基础类的查询方法
    public void select(){
    }
}

//定义一个类实现这个方法的查询方法

public class QueryMapper extends BaseMapper {

    @Override
    public void select() {
        System.out.println("查询方法");
    }
}

//定义一个代理类去继承你想代理的方法

public class ProxyMapper  extends  QueryMapper{

    @Override
    public void select() {
        System.out.println("代理方法");
        super.select();
    }
}

我们测试下

    public static void main(String[] args) {
        //正常的创建调用查询方法
        BaseMapper queryMapper = new QueryMapper();
        queryMapper.select();
        System.out.println("=====================");
        //代理的形式调用方法
        BaseMapper proxyMapper = new ProxyMapper();
        proxyMapper.select();
    }
    //打印出来
  	查询方法
	=====================
	代理方法
	查询方法

缺点:这种继承的形式需要写大量的继承关系,创建大量的类,代理类过多

聚合-接口形式实现静态代理

/**
 * 基础接口
 */
public interface BaseMapper {
	//定义查询接口
     void select();
}

一个实现类

/**
 * 搜索方法
 */
public class SelectMapper implements BaseMapper {


    @Override
    public void select() {
        System.out.println("select * from xxx");
    }
}

聚合-接口形式实现静态代理,创建一个代理对象需要那些条件。

  1. 代理对象要和目标对象实现同一个接口
  2. 代理对象存在一个属性接收目标对象
  3. 代理对象的构造方法注入目标对象

创建一个代理对象,

/**
 * 代理对象
 */
public class ProxyMapper  implements BaseMapper {

    private BaseMapper baseMapper ;

    public ProxyMapper(BaseMapper baseMapper) {
        this.baseMapper = baseMapper;
    }

    @Override
    public void select() {
        System.out.println("代理方法");
        baseMapper.select();
    }
}

我们调用下

   public static void main(String[] args) {
        //正常的创建调用查询方法
        BaseMapper queryMapper = new SelectMapper();
        queryMapper.select();
        System.out.println("=====================");
        //代理的形式调用方法
        BaseMapper proxyMapper = new ProxyMapper(queryMapper);
        proxyMapper.select();
    }
	打印:
	select * from xxx
	=====================
	代理方法
	select * from xxx

如果说我们要在查询方法之前先做条数统计count的功能 ,那么我们需要新增代理对象

public class CountMapper implements BaseMapper {

    private BaseMapper baseMapper ;

    public CountMapper(BaseMapper baseMapper) {
        this.baseMapper = baseMapper;
    }

    @Override
    public void select() {
    //统计方法
        System.out.println("统计方法");
        baseMapper.select();
    }
public static void main(String[] args) {
        //正常的创建调用查询方法
        BaseMapper queryMapper = new SelectMapper();
        queryMapper.select();
        System.out.println("=====================");
        //代理的形式调用方法
        BaseMapper proxyMapper = new ProxyMapper(queryMapper);
        proxyMapper.select();
        System.out.println("=====================");
        //先执行  代理->新增统计方法->查询
        BaseMapper proxy = new ProxyMapper(new CountMapper(new SelectMapper()));
        proxy.select();
    }
    打印:
    select * from xxx
	=====================
	代理方法
	select * from xxx
	=====================
	代理方法
	统计方法
	select * from xxx

很明显,我们这种聚合-接口的形式,能够很灵活去在目标对象的方法上 做各种的扩展。上面这个例子,也可以看出代理对象和目标对象的关系是相对的。
但是还是会存在大量的代码量,所以人们开始思考如何能够动态的生成满足我们需要的代理对象来帮我们实现我们想要的功能。

小总结下:仔细看来这些静态代理的形式,会发现这是一种编程的多态运用,多态的定义很广,也很灵活。

动态代理

JDK动态代理

在JDK的java.lang.reflect.Proxy类newProxyInstance方法

	/**
	* 返回指定接口的代理类的实例,该实例将方法调用分派到指定的调用处理程序。
	* @param   loader 类加载器
	* @param   interfaces 接口集
	* @param   h 将方法的调用分派给调用处理程序
	* @return  返回一个代理对象
	*/	
 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h){
}

模仿mybatis的动态代理

我们试着去调用这个方法生成一个代理对象
首先我们先定义一个接口UserDao

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Select {

    String value() default "";
}

public interface UserDao {

    @Select("select * from xxx")
    String select();
    
}

我们写一个方法去调用Proxy的生成代理类方法

public class MapperFactory {
    public static Object getMapper(Class interfaces) {
        //interfaces  为目标对象实现的多个接口
        Class[] classes = {interfaces};
        //获取接口集的代理对象
        Object o = Proxy.newProxyInstance(MapperFactory.class.getClassLoader(),//类加载器
                classes,//接口集
                new MapperInvocationHandler());//指定的调用处理程序
        return o;
    }
}
//创建一个实现InvocationHandler接口的实现类 MapperInvocationHandler
/**
 * 模拟mybatis框架的mapper接口动态代理实现
 * */
public class MapperInvocationHandler implements InvocationHandler {
	//invoke  在代理对象中调用该方法 转入相应的目标对象方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	//我们自定义一些方法的实现  和 前后增强
        System.out.println("链接数据库");//实现一个数据库链接的操作呀 
        Select annotation = method.getAnnotation(Select.class);
        System.out.println(annotation.value());//处理一下方法的注解逻辑呀
        return method.getReturnType().newInstance();//根据方法的返回对象 可以自定义
    }
}
}

我们调用一下

public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        UserDao userDao = (UserDao) MapperFactory.getMapper(UserDao.class);
        userDao.select();
    }
    打印:
    链接数据库
	select * from xxx

在调用Proxy.newProxyInstance方法后,内存中会注入一个代理对象,这个代理对象实现了你前面传入的所有interfaces[] 接口方法。
这个代理对象是存在内存中的,不是我们能看到的一个.java文件或者一个.class文件。
Mybatis框架的设计思路就是通过代理的形式来处理mapper接口。

我们的这种调用是模仿mybatis中的引用,是通过代理对象来实现mapper接口;

模仿Spring-aop的动态代理

接下来我们来模仿Spring-aop的动态代理,他是根据目标对象来做代理增强的。

//创建一个实现类  实现UserDao.select方法
public class UserDaoImp implements UserDao {
    @Override
    public String select() {
        System.out.println("实现类方法");
        return "实现imp";
    }
}

我们要对这个UserDaoImp.class类做代理
首先指定方法调用处理程序 InvocationHandler

/**
 * 模拟Spring-aop形式的动态代理实现
 */
public class AopInvocationHandler implements InvocationHandler {

    private Object target;

    public AopInvocationHandler(Object object) {
        this.target = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("aop-before method");//@before  前置增强 方法

        Object invoke = method.invoke(target, args);//目标对象自身方法逻辑和处理结果

        System.out.println("aop-after method");//@after 后置增强  方法
        return invoke;
    }
}
//模拟的工厂类
public class AopProxyFactory {
    public static Object getMapper(Object target) {
        //interfaces  为目标对象实现的多个接口
        Class[] classes = target.getClass().getInterfaces();//获取对象所有的接口class集合
        //获取接口集的代理对象
        Object o = Proxy.newProxyInstance(AopProxyFactory.class.getClassLoader(),//类加载器
                classes,//接口集
                new MapperInvocationHandler(target));//目标对象传入  指定的调用处理程序
        return o;
    }
}

我们来调用他

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        UserDao userDao = (UserDao) AopProxyFactory.getMapper(new UserDaoImp());
        userDao.select();
    }
	
	打印:
	aop-before method
	实现类方法
	aop-after method

这种我们是以目标对象 UserDaoImp 生成的代理对象 $Proxy0
本质上还是调用目标对象的select()方法,但是可以在方法的前后做自己的逻辑增强处理。
至于Proxy.newProxyInstance方法中是如何生成代理对象的让我们走进方法的源码。

走进Proxy.newProxyInstance方法

笔者会待大家走一下方法的主线,当然很多细节还需要读者去自己深入的了解下,看源码一定要先弄清方法的主线。

//关键类
package java.lang.reflect.Proxy;
  
 /**
	* 返回指定接口的代理类的实例,该实例将方法调用分派到指定的调用处理程序。
	* @param   loader 类加载器
	* @param   interfaces 接口集
	* @param   h 将方法的调用分派给调用处理程序
	* @return  返回一个代理对象
	*/	
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) throws IllegalArgumentException{
        
		Objects.requireNonNull(h);//InvocationHandler不能传null
		final Class<?>[] intfs = interfaces.clone();
		//获取代理对象class  com.sum.proxy.$Proxy0
		Class<?> cl = getProxyClass0(loader, intfs);
		//获取代理对象的构造方法 生成一个有参的构造方法 &Proxy0(InvocationHandler h)
		final Constructor<?> cons = cl.getConstructor(constructorParams);
		final InvocationHandler ih = h;
		if (!Modifier.isPublic(cl.getModifiers())) {
		  AccessController.doPrivileged(new PrivilegedAction<Void>() {
		      public Void run() {
		          cons.setAccessible(true);
		          return null;
		      }
		  });
		}
		//实例化 代理对象  &Proxy0(InvocationHandler h)
		return cons.newInstance(new Object[]{h});
    }

方法
Class<?> getProxyClass0(ClassLoader loader,Class<?>… interfaces);

 private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
        // 有个缓存机制,如果存在就返回代理对象
        // 否则通过ProxyClassFactory创建一个代理class
        return proxyClassCache.get(loader, interfaces);
    }
proxyClassCache 属性;
//a cache of proxy classes
//代理类的缓存容器
WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

WeakCache.get(K key, P parameter) ; 缓存容器的get方法

// p  interfaces[]
public V get(K key, P parameter) {

      Object cacheKey = CacheKey.valueOf(key, refQueue);
      ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey)if (valuesMap == null) {
          ConcurrentMap<Object, Supplier<V>> oldValuesMap
              = map.putIfAbsent(cacheKey,
                                valuesMap = new ConcurrentHashMap<>());
          if (oldValuesMap != null) {
              valuesMap = oldValuesMap;
          }
      }
      // 上面都不用在意   硬要理解的话 可以理解成 程序在帮我们申请内存 初始化容器和数据记录


	//第一个很关键的方法  
	//KeyFactory.apply(ClassLoader classLoader, Class<?>[] interfaces);
	//subKey是把interfaces封装在里面
      Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
      Supplier<V> supplier = valuesMap.get(subKey);
	//WeakCache.Factory类
      Factory factory = null;
	
	//自旋
      while (true) {
          if (supplier != null) {
              // supplier might be a Factory or a CacheValue<V> instance
              //类型可能是一个  Factory 或者  CacheValue<V>实例
              //第三步   我们调用这个 supplier 的get方法,这个时候 supplier被第二步赋值
              // 等同于调用  Factory.get()方法 
              V value = supplier.get();
              if (value != null) {
                  return value;
              }
          }
          //第一步  创建一个工厂  
          if (factory == null) {
              factory = new Factory(key, parameter, subKey, valuesMap);
          }
          
          if (supplier == null) {
              supplier = valuesMap.putIfAbsent(subKey, factory);
              if (supplier == null) {
                  // successfully installed Factory
                  //第二步  得到上面创建的工厂  这个时候supplier被工厂赋值
                  supplier = factory;
              }
          } else {
              if (valuesMap.replace(subKey, supplier, factory)) {
                  supplier = factory;
              } else {
                  supplier = valuesMap.get(subKey);
              }
          }
      }
  }

第三步调用 方法 WeakCache.Factory类实现了Supplier.get方法

   @Override
        public synchronized V get() { // serialize access
            // 自身检查 
            Supplier<V> supplier = valuesMap.get(subKey);
            if (supplier != this) {
            	//返回null  重新加入 外层自旋
                return null;
            }
            // create new value 
            V value = null;
            try {
            	//最关键的方法  通过ProxyClassFactory创建一个代理class
            	//调用 Class<?> apply(ClassLoader loader, Class<?>[] interfaces)
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // 创建失败 清除
                    valuesMap.remove(subKey, this);
                }
            }
            // 断言
            assert value != null;
            return value;
        }
    }

//在内存中动态生成代理对象的类class
Class<?> apply(ClassLoader loader, Class<?>[] interfaces)

 @Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

     Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
     //循环接口class集合  主要做一些判断
     for (Class<?> intf : interfaces) {
         Class<?> interfaceClass = null;
         try {
         //拿到这个 接口的class
             interfaceClass = Class.forName(intf.getName(), false, loader);
         } catch (ClassNotFoundException e) {
         }
         /*
          * 判断这个class是一个接口
          */
         if (!interfaceClass.isInterface()) {
             throw new IllegalArgumentException(
                 interfaceClass.getName() + " is not an interface");
         }
         /*
          *判断这个接口是否重复
          */
         if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
             throw new IllegalArgumentException(
                 "repeated interface: " + interfaceClass.getName());
         }
     }

	 //*******开始处理一些代理对象相关的属性 **********
     String proxyPkg = null;     // 代理类的包路径 类似 package java.xxx.xxx
     int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

     /*
      * 记录非公共代理接口的程序包,以便在同一程序包中定义代理类。
      * 验证所有非公共代理接口都在同一程序包中。
      * 这个不在主流成中 一般不会进到循环里
      **/
     for (Class<?> intf : interfaces) {
         int flags = intf.getModifiers();
         if (!Modifier.isPublic(flags)) {
             accessFlags = Modifier.FINAL;
             String name = intf.getName();
             int n = name.lastIndexOf('.');
             String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
             if (proxyPkg == null) {
                 proxyPkg = pkg;
             } else if (!pkg.equals(proxyPkg)) {
                 throw new IllegalArgumentException(
                     "non-public interfaces from different packages");
             }
         }
     }
	//处理代理类的 package 路径
     if (proxyPkg == null) {
         // 没有非公共代理的接口 我们采用 com.sun.proxy 包路径
         // ReflectUtil.PROXY_PACKAGE = com.sun.proxy
         proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
     }

     /**
      * 处理proxyName代理类名
      */
     long num = nextUniqueNumber.getAndIncrement();//获取编号 
     // 所有代理类名称的前缀  String proxyClassNamePrefix = "$Proxy"
     // com.sun.proxy. + $Proxy + 0  当前的代理类的名称
     String proxyName = proxyPkg + proxyClassNamePrefix + num;

     //******生成指定的 代理类 class ********************
     //调用 ProxyGenerator.generateProxyClass 生成代理类的字节码 
     byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
     //调用神奇的JVM虚拟机的bean方法 将一个class byte[]字节 编译成内存对象
     //private static native Class<?> defineClass0(ClassLoader loader, String name,byte[] b, int off, int len); 返回class
     return defineClass0(loader, proxyName,
                             proxyClassFile, 0, proxyClassFile.length);
 }
}

调用 ProxyGenerator.generateProxyClass 生成代理类的字节码动态代理的核心方法

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
	  //生成构建器
      ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
      //generateClassFile 获取class字节
      final byte[] var4 = var3.generateClassFile();
      //boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction(
      "sun.misc.ProxyGenerator.saveGeneratedFiles"));
      //这个boolean表示生成的代理对象是否保存到本地,因为这个类只是被加载到内存中,默认是不保存
      if (saveGeneratedFiles) {
      //开始写入操作通过流将 内存中的代理对象生成 .class文件
          AccessController.doPrivileged(new PrivilegedAction<Void>() {
              public Void run() {
                  try {
                      int var1 = var0.lastIndexOf(46);
                      Path var2;
                      if (var1 > 0) {
                          Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                          Files.createDirectories(var3);
                          var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                      } else {
                          var2 = Paths.get(var0 + ".class");
                      }

                      Files.write(var2, var4, new OpenOption[0]);
                      return null;
                  } catch (IOException var4x) {
                      throw new InternalError("I/O exception saving generated file: " + var4x);
                  }
              }
          });
      }
      //返回代理对象的字节
      return var4;
  }

generateClassFile方法处理代理对象字节

 private byte[] generateClassFile() {
 		//这里的this是 ProxyGenerator 代理对象构造器 
 		//添加  Object的 hashCode  equals  toString 方法
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        Class[] var1 = this.interfaces;//目标对象的接口集
        int var2 = var1.length;

        int var3;
        Class var4; 
        //将目标对象接口集的所有方法 添加到代理对象构造器中 
        for(var3 = 0; var3 < var2; ++var3) {
            var4 = var1[var3];//获取到其中一个接口
            Method[] var5 = var4.getMethods();//获得接口中所有的方法集
            int var6 = var5.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];//拿到方法集中的一个方法 
                this.addProxyMethod(var8, var4);//将方法添加到构造器中 var8=select()方法  var4 = UserDao这个接口对象
            }
        }
		//拿到这个方法集合  这个集合就是上面处理好的所有的方法
        Iterator var11 = this.proxyMethods.values().iterator();
        List var12;
        while(var11.hasNext()) {
            var12 = (List)var11.next();
            //检查返回类型
            checkReturnTypes(var12);
        }

        Iterator var15;
     	//generateConstructor() 添加代理对象的构造方法
     	//这个面是写死的 代理对象的有参数 参数:InvocationHandler var1
         this.methods.add(this.generateConstructor());
         var11 = this.proxyMethods.values().iterator();

         while(var11.hasNext()) {
             var12 = (List)var11.next();
             var15 = var12.iterator();
             while(var15.hasNext()) {
             //添加 Proxy方法  代理对象 默认继承Proxy类 包含 属性  protected InvocationHandler h;
                 ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                 this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                 this.methods.add(var16.generateMethod());
             }
         }
         this.methods.add(this.generateStaticInitializer());
		//判断方法和属性的长度
        if (this.methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        } else if (this.fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        } else {
        //**************从这开始 将所有的方法写入********
            this.cp.getClass(dotToSlash(this.className));
            this.cp.getClass("java/lang/reflect/Proxy");
            var1 = this.interfaces;
            var2 = var1.length;
            for(var3 = 0; var3 < var2; ++var3) {
                var4 = var1[var3];
                this.cp.getClass(dotToSlash(var4.getName()));
            }
            this.cp.setReadOnly();
            //创建流
            ByteArrayOutputStream var13 = new ByteArrayOutputStream();
            DataOutputStream var14 = new DataOutputStream(var13);
			//写入
            var14.writeInt(-889275714);
            var14.writeShort(0);
            var14.writeShort(49);
            this.cp.write(var14);
            var14.writeShort(this.accessFlags);
            var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
            var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
            var14.writeShort(this.interfaces.length);
            Class[] var17 = this.interfaces;
            int var18 = var17.length;

            for(int var19 = 0; var19 < var18; ++var19) {
                Class var22 = var17[var19];	
                var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
            }

            var14.writeShort(this.fields.size());
            var15 = this.fields.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                var20.write(var14);
            }
            
            var14.writeShort(this.methods.size());
            var15 = this.methods.iterator();

            while(var15.hasNext()) {
                ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                var21.write(var14);
            }

            var14.writeShort(0);
            //ByteArrayOutputStream 转成 byte[]字节
            //我们去打印Var13可能会发现  他的内容类似一个编译后的class文件
            return var13.toByteArray();
            
        }
    }

代理对象默认的generateConstructor()

private ProxyGenerator.MethodInfo generateConstructor() throws IOException {
		//有参构造方法 唯一参数 InvocationHandler
        ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);
        DataOutputStream var2 = new DataOutputStream(var1.code);
        this.code_aload(0, var2);
        this.code_aload(1, var2);
        var2.writeByte(183);
        var2.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V"));
        var2.writeByte(177);
        var1.maxStack = 10;
        var1.maxLocals = 2;
        var1.declaredExceptions = new short[0];
        return var1;
    }

再回到newProxyInstance方法 这个时候拿到了 cl
Class<?> cl = getProxyClass0(loader, intfs);

//关键类
package java.lang.reflect.Proxy;
  
 /**
	* 返回指定接口的代理类的实例,该实例将方法调用分派到指定的调用处理程序。
	* @param   loader 类加载器
	* @param   interfaces 接口集
	* @param   h 将方法的调用分派给调用处理程序
	* @return  返回一个代理对象
	*/	
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) throws IllegalArgumentException{
        
		Objects.requireNonNull(h);//InvocationHandler不能传null
		final Class<?>[] intfs = interfaces.clone();
		//获取代理对象class  com.sum.proxy.$Proxy0
		Class<?> cl = getProxyClass0(loader, intfs);
		//获取代理对象的构造方法 生成一个有参的构造方法 &Proxy0(InvocationHandler h)
		//我们获得$Proxy0 的构造方法  generateConstructor()生成的
		// constructorParams = InvocationHandler h
		final Constructor<?> cons = cl.getConstructor(constructorParams);
		
		//实例化 代理对象  &Proxy0(InvocationHandler h) 
		return cons.newInstance(new Object[]{h});
    }

我们跟过一遍就知道他代理代理的生成逻辑了,但是毕竟代理对象是在内存中,我们很难看到他的样子,如果存在.java或者.class文件是不是就更好理解了呢?
在源码的过程中 有过一个是否将代理对象保存到本地的判断,大家还记得吗?
我们可以开启他。

动态代理对象保存到本地

  public static void main(String[] args) throws IllegalAccessException, InstantiationException {
		// saveGeneratedFiles = true  保存代理对象到磁盘 地址默认为 com.sum.proxy 目录下
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //这个时候 userDao 就不是 UserDaoImp 而是他的代理对象 $Proxy0
        UserDao userDao = (UserDao) AopProxyFactory.getMapper(new UserDaoImp());
        userDao.select();
    }
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import com.example.spring2.proxy.UserDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

/**生成代理对象*/
public final class $Proxy0 extends Proxy implements UserDao {

	//代理对象默认继承Proxy类
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    
	//父类Proxy属性 protected InvocationHandler h;
	//构造方法
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    //静态块 获取到目标对象的方法
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            //获取到目标对象 UserDao的select方法
            //Class.forName(String className).getMethod(String name, Class<?>... parameterTypes)
            m3 = Class.forName("com.example.spring2.proxy.UserDao").getMethod("select");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
	//目标对象的方法 
     public final String select() throws  {
        try {
       		//这就是为什么 代理对象可以和目标对象存在一样的功能。
        	//调用 InvocationHandler.invoke方法 传入目标对象的方法和入参
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    
    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
}

小总结下:代理是调用相同的方法,得到的处理逻辑可能一样,也可能不同,就是代理不一定是增强,很多现在人们说是增强方法,但是也可以是改变,改变这个方法。
就像 如果我们不去Object invoke = method.invoke(target, args);调用/目标对象自身方法逻辑 ,是不是也可以自己去书写他新的逻辑,返回同样的返回类型。所以我们出了代理增强,也是一种代理改变。

github: https://github.com/dxt1218/jdk-proxy

当然动态代理的实现有很多种,SpringAop中Cglib也可以实现动态代理,这个后续笔者可以再出一篇Cglib的动态代理的源码实现。
希望这篇文章能够有助于大家,有什么好的建议和疑问也可以留言交流,感谢阅读~~

;原文链接:https://blog.csdn.net/weixin_38899094/article/details/115655832
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:Java实现计网循环冗余检验算法 下一篇:没有了

推荐图文


随机推荐