我是靠谱客的博主 虚拟绿草,最近开发中收集的这篇文章主要介绍SpringAop之JDK动态代理源码解析保姆级SpringAop之JDK动态代理源码解析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

SpringAop之JDK动态代理源码解析

摘要

Aop代理模式看过Spring源码同学都知道很多用了代理模式,主要对其目标类方法调用前后做增强拦截,不改变目标方法情况下实现插拔。只需要定义一组代理类实现接口,通过反射方式调用。

演示

声明目标类接口、方法

//接口
public interface UserService {
    int save(String name);

    void update(String name);
}
//实现类
public class UserServiceImpl implements UserService{
    @Override
    public int save(String name) {
        System.out.println(name+"save success");
        return 1;
    }

    @Override
    public void update(String name) {
        System.out.println(name+"update success");
    }
}

定义代理类 (关键)

//代理类 实现InvocationHandler接口 重写invoke方法
public class UserServiceProxy implements InvocationHandler {
    //目标类
    private Object target;

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

    //invoke 负责调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行前操作....");
        Object result = method.invoke(target, args);
        System.out.println("执行后操作....");
        return result;
    }
}

启动调用

public class TestJdkProxy {
    public static void main(String[] args) throws IOException {
    //newProxyInstance 创建代理类
       UserService proxy= (UserService)Proxy.newProxyInstance(UserService.class.getClassLoader(),
                new Class[]{UserService.class},
                new UserServiceProxy(new UserServiceImpl()));
        //委托代理类调用目标方法 代码会进入invoke方法
        proxy.save("nijo");
        proxy.update("huhu");
    }
}
执行前操作....
nijosave success
执行后操作....
执行前操作....
huhuupdate success
执行后操作....

源码扣核心

1. 跟newProxyInstance() 方法 3个参数

 				public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
          //检测代理类不为空
        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);

2.跟 getProxyClass0()方法

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);
    }

3. 继续跟ProxyClassFactory类

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) {
        /**省略.....
            中间做了一些校验,校验是否接口、接口是否重复
            **/
        
        //生成代理类class文件
          byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
        }

4. generateProxyClass()具体如何生成 (关键)

public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        //开始具体生成class
        final byte[] var4 = var3.generateClassFile();

5. 跟generateClassFile()方法 (关键)

private byte[] generateClassFile() {
        //生成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;
            //生成目标类所有方法进行代理,按照演示这里会有save()update()方法生成
            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }
        Iterator var11 = this.proxyMethods.values().iterator();

        List var12;
        while(var11.hasNext()) {
            var12 = (List)var11.next();
            checkReturnTypes(var12);
        }

        Iterator var15;
        try {
           //添加构造方法 设置参数代理类接口
            this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();

代理类讲述

generateClassFile()为主要生成代理类class字节码,单独生成class看看张什么样

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                "com.sun.proxy.$Proxy0", new Class[]{UserService.class});
        FileOutputStream outputStream=new FileOutputStream("~/$Proxy1.class");
        outputStream.write(proxyClassFile);
        outputStream.flush();
        outputStream.close();
//继承Proxy 实现目前类UserService
public final class $Proxy0 extends Proxy implements UserService {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;
    //构造方法 参数代理类实现InvocationHandler接口 
    public $Proxy0(InvocationHandler var1) throws  {
        //将代理类设置到父类Proxy
        super(var1);
    }
   //euqals方法
    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);
        }
    }
    //目标类UserService # Save方法
    public final int save(String var1) throws  {
        try {
            //通过父类Proxy到代理类重写invoke方法调用 代码就会走到演示中UserServiceProxy # invoke方法
            return (Integer)super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
//Object # toString
    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);
        }
    }
//目标类UserService # update方法
    public final void update(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    //Object # hachCode方法
    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);
        }
    }
    //加载class时候初始化资源
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.example.beanaop.jdkProxy.UserService").getMethod("save", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.beanaop.jdkProxy.UserService").getMethod("update", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

补充

源码扣核心第2步有讲到get()如果之前未加载过,执行ProxyClassFactory类生成,它是怎么调用ProxyClassFactory.apply()的呢?

 public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        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
        //以上缓存未命中,就使用ProxyClassFactory.apply生成,这样就过度到第3步了
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));

总结

  1. 源码核心方法generateClassFile 生成代理类$Proxy0。
  2. $Proxy0代理类 继承Proxy类,实现目标类接口UserService。
  3. 代理类包含 目标类接口UserService所有方法进行代理,有自身构造函数,实列化传递参数代理类实现InvocationHandler接口 ,并设置Proxy父类。
  4. 标类接口UserService所有方法进行代理 通过调用Prxoy父类InvocationHandler 进行路由到代理类UserServiceProxy#invoke方法调用。

最后

以上就是虚拟绿草为你收集整理的SpringAop之JDK动态代理源码解析保姆级SpringAop之JDK动态代理源码解析的全部内容,希望文章能够帮你解决SpringAop之JDK动态代理源码解析保姆级SpringAop之JDK动态代理源码解析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部