动态代理源码解析之JDK

本文详细解析了JDK动态代理的工作原理及其实现过程,包括如何通过实现InvocationHandler接口创建代理类,并通过源码展示了代理类的生成与实例化流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序员基本都知道有个模式叫代理模式,其实质就是调用由代理类发起,再由代理类来进行调用真实的业务类来调用,实现业务控制,在代理类的处理中,可以在真实的业务类调用前面和后面进行逻辑处理;

而动态代理跟普通的代理模式在代码编写上是有区别的,动态代理的代理类class是动态生成的;

动态代理的应用场景很广,最被人熟知的当属spring的AOP,AOP的应用场景非常广泛,比如权限控制,缓存等等

动态代理的实现有:jdk动态代理和cglib动态代理,本篇博文尝试从源码角度来看看jdk动态代理是怎么实现的

先来看看jdk动态代理怎么用,上代码

  • UserService

    public interface UserService {
        void add();
    }
  • UserServiceImpl

    
    public class UserServiceImpl implements UserService {
        @Override
        public void add() {
            System.out.println("add");
        }
    }
  • MyInvocationHandler

    
    public class MyInvocationHandler implements InvocationHandler {
        private Object target;
    
        public MyInvocationHandler(Object target) {
            super();
            this.target = target;
        }
    
        public Object getProxy() {
            return Proxy.newProxyInstance(Thread.currentThread()
                            .getContextClassLoader(), target.getClass().getInterfaces(),
                    this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("----- before -----");
            Object result = method.invoke(target, args);
            System.out.println("----- after -----");
            return result;
        }
    }
  • Test

    public class Test {
        public static void main(String[] args) {
            UserService userService = new UserServiceImpl();
            MyInvocationHandler invocationHandler = new MyInvocationHandler(
                    userService);
    
            UserService proxy = (UserService) invocationHandler.getProxy();
            proxy.add();
        }
    }
  • main方法执行结果

    
    ----- before -----
    add
    ----- after -----
  • jdk动态代理代理类需要实现java.lang.reflect.InvocationHandler接口,从包名可以看出,jdk动态代理应该是用反射来实现的

看看代码

  • 在main方法中new了一个实现类来赋值给接口,而不是直接定义实现类,最重要的原因是jdk动态代理只支持接口的动态代理,被代理的类都必须要有接口
  • 动态代理的入口是getProxy()方法,getProxy()方法实现为:newProxyInstance,接受参数:(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);这里的ClassLoader为当前线程上下文的ClassLoader,interfaces为被代理类的所有接口数组
  • 看到这里,想必jdk动态代理的核心逻辑就在这个newProxyInstance方法里;这里贴下源码

    
    @CallerSensitive
    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);
            }
            //生成class的核心逻辑
            Class<?> cl = getProxyClass0(loader, intfs);
            // 生成完以后,那就是根据生成的class来产生代理实例
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    
                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);
            }
    }
    • 这里小小吐槽下,jdk源码也用很多简写,个人不大推崇这种写法,比如:intfs
    • 再看getProxyClass0方法,用到的WeakCache后面专门写文章讲解,这里知道是用来做缓存的就行
      
      //采用WeakCache缓存代理class
      private static final WeakCache<ClassLoader, Class<?>[], Class<?>> 
      proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
      private static Class<?> getProxyClass0(ClassLoader loader,
                                             Class<?>... interfaces) {
          if (interfaces.length > 65535) {
              throw new IllegalArgumentException("interface limit exceeded");
          }
          //get方法先去缓存查找,如果没找到那么用ProxyClassFactory来生成
          //再进入get方法看,第一行代码就是Objects.requireNonNull(interfaces);
          //从这里看出jdk动态代理中被代理的类必须实现接口
          return proxyClassCache.get(loader, interfaces);
      }

未完(时间关系后续补)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值