动态代理及JDK代理源码解析

动态代理及JDK代理源码解析

参考:JDK动态代理-超详细源码分析 - 简书 (jianshu.com)

一、为什么需要动态代理

什么是代理模式?

代理模式就是给某个对象(后称为初始对象)创建一个代理对象,其他对象可以通过代理对象(简称代理)来控制初始对象。

初始对象的代码并不会改变,但是因为有代理对象的存在,可以在执行初始对象的执行过程之外再加一些操作,比如说:执行初始对象向数据库添加了一条数据,然后又通过代理对象删除了这条数据,这个例子比较难理解,因为肯定会问这样的意义是什么?

这里写者主要向强调的是代理是可以操作初始对象的参数和结果,可以通过增加更多的操作达到更多的目的,而不改变原来的代码,至于这个目的是增强还是削弱,这本身就是不同情景下不同的定义的问题,这里只是从客观的角度去看。

说回来,一个更恰当的例子我们可以在执行初始对象删除一条数据,并在这个操作的前后分别打印“我要删除了!”和“我已经删除了!”

静态代理:

有动态代理那么一定就会有静态代理,那么什么是静态代理呢?

静态代理和动态代理的主要区别就在于:在程序运行前是否已经存在编译好的代理类

这句话是不是很绕口,这里可以先进行预先解释一下:

​ 对于被代理类来说如果要加强它的操作常见的方式就是再创建一个类(也就是代理类)持有这个被代理类的对象,然后将增强的操作逻辑放入其中,那么这个就需要实现编写这个类的代码,那么如果每个被代理类都需要编写一个代理类的代码,这个情况下,自然而然就会出现一个需求:一次编写,到处运行,针对某种需求统一编写一个代理类,使得这个代理类可以应用于多个被代理对象,而这种需不需要为每个类编写代理类的差别就是动态代理和静态代理的之间的区别

还是没有理解,接着向下看:

静态代理就是在程序运行前就已经存在了编译好的代理类

实现步骤:
  1. 定义业务接口
  2. impl(被代理类)实现业务接口
  3. 定义代理类也实现业务接口
  4. 最后调用代理类实现增强
实现代码:

业务接口:

public interface IUserService {

    public void select();
}

业务接口实现类:

public class UserServiceImpl implements IUserService{

    @Override
    public void select() {
        System.out.println("method invoke in impl!");
    
}

代理类:

public class IUserServiceProxy implements IUserService{

    private IUserService iUserService;

    public IUserServiceProxy(IUserService iUserService) {
        this.iUserService = iUserService;
    }

    @Override
    public void select() {
        System.out.println("方法执行前加强");
        iUserService.select();
        System.out.println("方法执行后加强");
    }
}

服务调用对象:

public class StaticProxyTest {
    public static void main(String[] args) {
        IUserService target = new UserServiceImpl();
        /*创建静态代理对象*/
        IUserService proxy = new IUserServiceProxy(target);
        /*实现增强*/
        proxy.select();
    
}
分析:

这样也能实现代理的功能但是静态代理有一些问题的缺点的存在:

  1. 代理类和被代理类实现了相同的接口,这样会导致代码重复,如果接口增加一个方法,那么除了被代理类要实现这个方法,代理类也要实现这个方法
  2. 这个代理类只能服务一个对象,或者一个类型的对象,并不能广泛复用,如果需要给其他对象也增强就需要创建更多的代理类

动态代理:

那么因为静态代理有这样那样的缺点,那么就需要一种新的方法来解决这样的一些问题,这里很显然的就可以考虑到在代码运行的过程中根据不同的对象相应的创建不同适配的代理类,也就是动态代理:

在程序运行期间根据需要动态创建代理类及其实例来完成具体的功能,常用动态代理的方式为:

  • JDK动态代理
  • CGLIB动态代理
JDK动态代理
实现步骤:
  1. 创建被代理的类和接口
  2. 创建InvocationHandler接口的实现类,在invoke方法中实现代理逻辑
  3. 通过Proxy 的静态方法newProxyInstance创建代理对象
  4. 使用代理对象
实现代码:

代理的接口和类-> 复用上面的IUserService 和 UserServiceImpl

InvocationHandler 接口的实现类:

public class MyInvocationHandler implements InvocationHandler {

    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行前增强!");
        Object returnValues = method.invoke(target,args);
        System.out.println("执行后增强!");
        return returnValues;
    }
}

创建代理对象并使用代理对象:

public class JdkProxyTest {

    public static void main(String[] args) {
        IUserService target = new UserServiceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(target);

        /**
         * parameter1: 指定代理类的类加载器(为什么一定要指定类加载器呢?)
         * parameter2: 传入代理类要实现的接口(这样代理类和被代理类就会实现相同的接口)
         * parameter3: 用来处理方法调用,即对应的代理逻辑
         */
        IUserService proxy = (IUserService) Proxy.newProxyInstance(
                JdkProxyTest.class.getClassLoader(),
                target.getClass().getInterfaces(),
                handler);
        /*调用代理方法*/
        proxy.select();
    }
}

这里我们并没有为每一个被代理的类去创建一个对应的代理类,而是动态的根据代码去创建了代理对象(毕竟你自己写代理类的目的其实也是为了获取代理对象)

CGLIB动态代理:

这里有一个区分就是:

JDK代理是基于UserService -UserServiceImpl 这种实现接口的模式进行的带来,而被代理的类是UserServiceImpl 对象

这时动态代理的对象必须实现一个或多个接口,那么自然而然就会有一个需求:如何代理没有实现接口的类?为什么JDK代理的类必须要实现接口才能代理?我们分为两部分来说明白,而第二个问题放到第二个标题JDK动态代理是怎样产生的方面去说明。

这个情况下就可以通过CGLIB动态代理来解决第一个问题:

CGLIB:Code Generation Libary 是一个高性能代码生成包,采用非常底层的字节码技术,针对目标类生成一个子类,并对子类进行增强

实现步骤:
  1. 创建被代理的类和对象
  2. 创建实现了MethodInterceptor 的代理类
  3. 封装代理逻辑
  4. 客户端调用

被代理的类:UserDao

public class UserDao {

    public void addUser() {
        System.out.println("Add a user instance!");
    }

    public void deleteUser() {
        System.out.println("Delete a user instance!");
    }
}

切面类:UserDaoAspect

切面类本质上是增强逻辑的具体实现,而被代理类封装的是增强逻辑的执行顺序

public class UserDaoAspect {
    public void invoke_before(){
        System.out.println("invokeBefore has completed;");
    }

    public void invoke_after(){
        System.out.println("invokeBefore has completed;");
    }
}

代理类:CglibProxy

/**
 * @BelongsProject: spring_learn
 * @BelongsPackage: com.wang.cglib
 * @Author: Wang Haipeng
 * @CreateTime: 2021-11-20 20:56
 * @Description: cglib动态代理类实现方法拦截器
 */
public class CglibProxy implements MethodInterceptor {

    /**
     * 创建代理类对象
     * @param o 被代理类对象
     * @return 代理类对象
     */
    public Object creatProxy(Object o){

        /*1、创建一个增强类对象*/
        Enhancer enhancer =new Enhancer();
        /*2、设置被代理类(参数就是被代理类的反射)*/
        enhancer.setSuperclass(o.getClass());
        /*3、添加回调函数(就是当类创建完成后同步通知),通过函数指针调用函数*/
        enhancer.setCallback(this);
        /*4、返回创建的代理类对象*/
        return enhancer.create();
    }
    

    /**
     *
     * @param o 被代理类对象(由CGLIB生成的)
     * @param method 被代理类对象的方法(切点)
     * @param args 被代理对象中方法执行的参数(切点参数)
     * @param methodProxy 用于执行父类方法,方法执行器
     * @return 被代理对象初始方法的返回值
     * @Desciption 封装代理的执行顺序(执行具体逻辑在切面中)
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        /*1)声明切面对象*/
        UserDaoAspect userDaoAspect = new UserDaoAspect();
        userDaoAspect.invoke_before();
        /*2) 执行被代理对象的目标方法*/
        Object returnResult = methodProxy.invokeSuper(o,args);
        userDaoAspect.invoke_after();
        return returnResult;
    }
}

Cglib 测试类:CglibTest:

public class CglibTest {

    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();

        UserDao userDao = new UserDao();

        UserDao userDaoExtend = (UserDao) cglibProxy.creatProxy(userDao);

        userDaoExtend.addUser();
        userDaoExtend.deleteUser();
    }
}

实现效果:

image-20211124092614931

二、动态代理对象是如何产生的?

这部分就比较复杂了,初学的小伙伴们可能需要费一些力气了

这里插入一个主题:部署JDK源码环境:可以直接使用我的jdk源码阅读项目

,具体如何在idea 里面配置jdk阅读环境 这里就不赘述了,大家可以直接把我的项目拉下来使用:

OldClassmatesWang/Java_Source_Learn: 本地jdk1.8源码阅读项目 (github.com)

接下来就是源码的阅读了:这里看的是JDK动态代理实现的源码:

java.lang.reflect.Proxy.java

newInstance method

首先查看:Proxy.newInstance(classloader,interfaces,invocationHandler)

    /**

     *
     * @param   loader 指定更多类加载器 the class loader to define the proxy class
     * @param   interfaces 代理类实现的所有接口 the list of interfaces for the proxy class
     *          to implement
     * @param   h 实现了InvocationHandler 的类,也就是实现的代理类  the invocation handler to dispatch method invocations to
     * @return  代理类对象 a proxy instance with the specified invocation handler of a
     
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        /*检查这里传递InvocationHandler 实现类对象不为空*/
        Objects.requireNonNull(h);
        /*拷贝接口的类对象*/
        final Class<?>[] intfs = interfaces.clone();
        /*进行一些安全检测*/
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         *
         *  Look up or generate the designated proxy class.
         * 查询(在缓存中已经有)或生成指定的代理类实现接口的class对象。
         *  通过指定的类加载器和类实现的接口作为参数,查找出或生成代理类的类对象
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         * 通过已经设计好的调用处理器执行被代理类它的构造方法
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            /**
             * 得到代理类对象的构造函数
             * 这个构造函数的参数直接由constructorParams指定
             * 参数constructorParames为常量值:
             * private static final Class<?>[] constructorParams
             *  = { InvocationHandler.class };
             */
            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;
                    }
                });
            }
            /*通过构造方法构造一个新的实例
            传入参数是这个实例的实现类
            也就是代理对象
            */
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

这段代码看着复杂其实目标很简答:

  • 核心代码:

    •     /*
           *
           *  Look up or generate the designated proxy class.
           * 查询(在缓存中已经有)或生成指定的代理类实现接口的class对象。
           *  通过指定的类加载器和类实现的接口作为参数,查找出或生成代理类的类对象
           */
          Class<?> cl = getProxyClass0(loader, intfs);
      
  • 整体功能:

    • 整体功能就是通过上面的这个代码获取到动态生成的代理类的类对象,然后通过类对象获取它的构造函数,再通过构造函数创建实例
  • 问题:

    • 这里虽然大概看出了实例是通过生成的代理类的类对象产生的,但是实际上其实还是没有说明,代理类的类对象是如何产生的
  • 问题转换:

    • 现在问题转换为:动态生成的代理类的类对象是如何产生的?
  • 传入参数:

    • 1)loader 指定的类加载器
    • 2)被代理类实现的接口的类对象
  • 下一个要查看的方法:

    • java.lang.reflect.Proxy.java

    • private static Class<?> getProxyClass0(ClassLoader loader,
                                             Class<?>... interfaces)
      
getProxyClass0 method
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        /*这个地方的意思就是说:如果说这个指定的类加载器实现了,并且实现了给定的接口,那么就返回缓存的代理类对象,否则就通过ProxyClassFactory 来创建代理类*/
        return proxyClassCache.get(loader, interfaces);
    }

proxyClassCache是什么?这里就比较复杂了

首先先看他的定义:(后面的一些内容因为我本身理解有限,就引用一部分参考博客的原文了)

   /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

是一个WeakCache 的对象,它刚刚调用的get方法是WeakCache 里的方法:

//K代表key的类型,P代表参数的类型,V代表value的类型。
// WeakCache<ClassLoader, Class<?>[], Class<?>>  proxyClassCache  说明proxyClassCache存的值是Class<?>对象,正是我们需要的代理类对象。
final class WeakCache<K, P, V> {

    private final ReferenceQueue<K> refQueue
        = new ReferenceQueue<>();
    // the key type is Object for supporting null key
    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();
    private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
        = new ConcurrentHashMap<>();
    private final BiFunction<K, P, ?> subKeyFactory;
    private final BiFunction<K, P, V> valueFactory;

  
    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }

其中map变量是实现缓存的核心变量,他是一个双重的Map结构: (key, sub-key) -> value

其中key是传进来的Classloader进行包装后的对象,

sub-key是由WeakCache构造函数传人的KeyFactory()生成的。

value就是产生代理类的对象,是由WeakCache构造函数传人的ProxyClassFactory()生成的。

产生sub-key的KeyFactory代码如下,这个我们不去深究,只要知道他是根据传入的ClassLoader和接口类生成sub-key即可。

private static final class KeyFactory
        implements BiFunction<ClassLoader, Class<?>[], Object>
    {
        @Override
        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
            /*根据实现接口的数量生成sub_key*/
            switch (interfaces.length) {
                case 1: return new Key1(interfaces[0]); // the most frequent
                case 2: return new Key2(interfaces[0], interfaces[1]);
                case 0: return key0;
                default: return new KeyX(interfaces);
            }
        }
    }

通过sub-key拿到一个Supplier<Class<?>>对象,然后调用这个对象的get方法,最终得到代理类的Class对象。

  • 整体功能:
    • 大体上这就是WeakCache类的作用:被代理类的类加载器和实现的类的接口(转换成一个Key对象)会作为key存在map里面,如果之前这个被加载过,则可以通过这种方式用key来获取对应已经生成好的,还在java缓存中的类的Class 对象
    • 这里我们明显是第一次调用,所以我们肯定是第一次生成的,所以接下来的关键还是看如何生成这个代理类的Class对象
  • 下一个要查看的方法:
    • java.lang.reflect.WeakCache.java
    • public V get(K key, P parameter)

java.lang.reflect.WeakCache.java

get
 public V get(K key, P parameter) {
        /**
         * param1:被代理类的类加载器
         * param2:被代理类的实现接口列表
         */

        /*检查parameter 不为空*/
        Objects.requireNonNull(parameter);

        /*清除无效缓存*/
        expungeStaleEntries();
        /*cacheKey就是(key, sub-key) -> value里的一级key,*/
        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        /**
         * 根据一级key得到 ConcurrentMap<Object, Supplier<V>>对象。
         * 如果之前不存在
         * 则新建一个ConcurrentMap<Object, Supplier<V>>和cacheKey(一级key)一起放到map中。
         */
        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;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        /*根据一级key得到 ConcurrentMap<Object, Supplier<V>>对象。
        如果之前不存在,则新建一个ConcurrentMap<Object, Supplier<V>>和cacheKey(一级key)一起放到map中。*/
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        /* 通过sub-key得到supplier*/
        Supplier<V> supplier = valuesMap.get(subKey);
        /*supplier实际上就是这个factory*/
        Factory factory = null;

        while (true) {
            /*如果缓存里有supplier ,那就直接通过get方法,得到代理类对象,返回,就结束了*/
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance

                /**
                 * 注意这里是死循环,所以是下面生成,然后赋值给这的
                 * 核心代码在这里,下面其实就是创建supplier
                 * supplier 是一个factory
                 * 这里调用get方法获取这个对应的代理类对象
                 */
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            if (factory == null) {
                /*下面的所有代码目的就是:
                如果缓存中没有supplier
                则创建一个Factory对象
                把factory对象在多线程的环境下安全的赋给supplier。
                 因为是在while(true)中,赋值成功后又回到上面去调get方法,返回才结束。*/
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }
  • 整体功能:

    • 这部分的代码主要就是将factory 创建并放到缓存当中
  • 问题:

    • 其实还没有写明是怎么生成的

    • 核心代码:

      • factory = new Factory(key, parameter, subKey, valuesMap);
        
  • 问题转换:

    • 现在问题转换为:factory是如何生成被代理对象的
  • 传入参数:

    • key:classloader
    • parameter:interfaces 实现的类
    • subkey:根据interfaces 生成的,和key一起组成第二层的key
    • valuemap:虚拟机中存储这写被代理类的hashmap
  • 下一个要查看的方法:

    • factory.get 这是WeakCache 的内部类方法
factory.get
   public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            //重新检查得到的supplier是不是当前对象
            if (supplier != this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            V value = null;
            try {
                 //代理类就是在这个位置调用valueFactory生成的
                 //valueFactory就是我们传入的 new ProxyClassFactory()
                //一会我们分析ProxyClassFactory()的apply方法
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // the only path to reach here is with non-null value
            assert value != null;

            // wrap value with CacheValue (WeakReference)
            //把value包装成弱引用
            CacheValue<V> cacheValue = new CacheValue<>(value);

            // put into reverseMap
            // reverseMap是用来实现缓存的有效性
            reverseMap.put(cacheValue, Boolean.TRUE);

            // try replacing us with CacheValue (this should always succeed)
            if (!valuesMap.replace(subKey, this, cacheValue)) {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }
    }

核心代码:

                value = Objects.requireNonNull(valueFactory.apply(key, parameter));

java.lang.reflect.Proxy.java

找到了valueFactory.apply 的实现点,是Proxy 的内部类ProxyClassFactory实现的。

/这里的BiFunction<T, U, R>是个函数式接口,可以理解为用TU两种类型做参数,得到R类型的返回值
private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names
        //所有代理类名字的前缀
        private static final String proxyClassNamePrefix = "$Proxy";
        
        // next number to use for generation of unique proxy class names
        //用于生成代理类名字的计数器
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
              
            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            //验证代理接口,可不看
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
            //生成的代理类的包名 
            String proxyPkg = null;     // package to define proxy class in
            //代理类访问控制符: public ,final
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            //验证所有非公共的接口在同一个包内;公共的就无需处理
            //生成包名和类名的逻辑,包名默认是com.sun.proxy,类名默认是$Proxy 加上一个自增的整数值
            //如果被代理类是 non-public proxy interface ,则用和被代理类接口一样的包名
            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");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            //代理类的完全限定名,如com.sun.proxy.$Proxy0.calss
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
            //核心部分,生成代理类的字节码
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                //把代理类加载到JVM中,至此动态代理过程基本结束了
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }
  • 整体功能:

    • 获取预计实现代理类的属性包括包名,包括验证访问修饰符等等,然后根据这些属性生成了对应的代理类的字节码,然后将这些字节码加载到java虚拟机当中,由此完成了动态代理

    • 核心代码:

      • byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                        proxyName, interfaces, accessFlags);
        
      • 再往下看就是如何生成这个字节码了,就超出本次分析的内容了

阅读源码断点:

到此为止其实阅读源码的内容已经明白了,JDK底层如何实现动态代理的过程其实我们也明白了,可以明确的几点就是:

  • 动态代理对于UserDaoImpl 会生成对应的代理类的Class对象,然后调用时会实例化这个Class对象,然后生成对应的代理类的实例
  • 为什么这个类一定要实现一个接口
    • image-20211124171133712
    • 其实就是这里的key0的问题
      • key0这个过程其实没有理解很透彻,希望大家和我来交流,我初步的理解就是因为key0不是弱引用(我这里就理解成有个类没有实现),所以代码中进行了限定无法将对应生成的Proxy存储到缓存中

再次引用了:

到这里其实已经分析完了,但是本着深究的态度,决定看看JDK生成的动态代理字节码是什么,于是我们将字节码保存到磁盘上的class文件中。代码如下:

package com.zhb.jdk.proxy;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;

import com.zhb.jdk.dynamicProxy.HelloworldImpl;

import sun.misc.ProxyGenerator;

/**
* @author ZHB
* @date 2018年8月31日下午11:35:07
* @todo TODO
*/
public class DynamicProxyTest {

 public static void main(String[] args) {

     IUserService target = new UserServiceImpl();
     MyInvocationHandler handler = new MyInvocationHandler(target);
     //第一个参数是指定代理类的类加载器(我们传入当前测试类的类加载器)
     //第二个参数是代理类需要实现的接口(我们传入被代理类实现的接口,这样生成的代理类和被代理类就实现了相同的接口)
     //第三个参数是invocation handler,用来处理方法的调用。这里传入我们自己实现的handler
     IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
             target.getClass().getInterfaces(), handler);
     proxyObject.add("陈粒");

     String path = "D:/$Proxy0.class";
     byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", HelloworldImpl.class.getInterfaces());
     FileOutputStream out = null;

     try {
         out = new FileOutputStream(path);
         out.write(classFile);
         out.flush();
     } catch (Exception e) {
         e.printStackTrace();
     } finally {
         try {
             out.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }

 }
}

运行这段代码,会在D盘生成一个名为$Proxy0.class的文件。通过反编译工具,得到JDK为我们生成的代理类是这样的:

// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 

import com.zhb.jdk.proxy.IUserService;
import java.lang.reflect.*;

public final class $Proxy0 extends Proxy
 implements IUserService
{

 private static Method m1;
 private static Method m2;
 private static Method m3;
 private static Method m0;
 //代理类的构造函数,其参数正是是InvocationHandler实例,
 //Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的
 public $Proxy0(InvocationHandler invocationhandler)
 {
     super(invocationhandler);
 }
  // Object类中的三个方法,equals,toString, hashCode
 public final boolean equals(Object obj)
 {
     try
     {
         return ((Boolean)super.h.invoke(this, m1, new Object[] {
             obj
         })).booleanValue();
     }
     catch (Error ) { }
     catch (Throwable throwable)
     {
         throw new UndeclaredThrowableException(throwable);
     }
 }

 public final String toString()
 {
     try
     {
         return (String)super.h.invoke(this, m2, null);
     }
     catch (Error ) { }
     catch (Throwable throwable)
     {
         throw new UndeclaredThrowableException(throwable);
     }
 }
 //接口代理方法
 public final void add(String s)
 {
     try
     {
         // invocation handler的 invoke方法在这里被调用,也就是封装的代理逻辑
         super.h.invoke(this, m3, new Object[] {
             s
         });
         return;
     }
     catch (Error ) { }
     catch (Throwable throwable)
     {
         throw new UndeclaredThrowableException(throwable);
     }
 }

 public final int hashCode()
 {
     try
     {
         // 在这里调用了invoke方法。
         return ((Integer)super.h.invoke(this, m0, null)).intValue();
     }
     catch (Error ) { }
     catch (Throwable throwable)
     {
         throw new UndeclaredThrowableException(throwable);
     }
 }

 // 静态代码块对变量进行一些初始化工作
 static 
 {
     try
     {
         m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
             Class.forName("java.lang.Object")
         });
         m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
         m3 = Class.forName("com.zhb.jdk.proxy.IUserService").getMethod("add", new Class[] {
             Class.forName("java.lang.String")
         });
         m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
     }
     catch (NoSuchMethodException nosuchmethodexception)
     {
         throw new NoSuchMethodError(nosuchmethodexception.getMessage());
     }
     catch (ClassNotFoundException classnotfoundexception)
     {
         throw new NoClassDefFoundError(classnotfoundexception.getMessage());
     }
 }
}

生成了Object类的三个方法:toString,hashCode,equals。还有我们需要被代理的方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值