理解动态代理底层

理解动态代理底层

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

根据我的理解:

步骤

  • Objects.requireNonNull(h);

    • 判断代理实例的调用处理程序对象不为空 也就是你目前实现的这个接口不为空
  • final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    
    • final Class<?>[] intfs = interfaces.clone();这个是获得你这个接口的克隆对象
    • final SecurityManager sm = System.getSecInvocationHandlerurityManager();这个是获得安全管理器,这里面是分配安全权限的地方。
      • 这个安全管理器的应用场景是:当运行未知的Java程序的时候,该程序可能有恶意代码(删除系统文件、重启系统等),为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时候就要启用Java安全管理器。
      • 权限分为以下类别:文件、套接字、网络、安全性、运行时、属性、AWT、反射和可序列化。
  • if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
    
    • 这里是判断安全管理器不为空,然后执行代理访问的方法,第一个是获得调用反射这个类的对象,第二个参数就是你自己写的实现了InvocationHandler的类的对象,第三个参数就是你代理的接口对象

    • ​ 这个方法的实现是

      •         private static void checkProxyAccess(Class<?> caller,
                                                     ClassLoader loader,
                                                     Class<?>... interfaces)
                {
                    SecurityManager sm = System.getSecurityManager();
                    if (sm != null) {
                        ClassLoader ccl = caller.getClassLoader();
                        if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
                            sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
                        }
                        ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
                    }
                }
        
      • SecurityManager sm = System.getSecurityManager();
        
        • 这个同样是拿到系统安全管理器
      •         if (sm != null) {
                    ClassLoader ccl = caller.getClassLoader();
                    if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
                        sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
                    }
                    ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
                }
        
        • 这个先判断管理器是否为空,不为空时
        • 1、获取Reflection调用反射这个类的对象的类加载器。
        • 2、判断调用我实现了InvocationHandler必须是系统类加载器的也就是AppClassLoader以及调用反射类的对象不能是系统类加载器(AppClassLoader)
        • 3、然后调用检查权限,检查的是运行时权限
        • 4、·ReflectUtil.checkProxyPackageAccess(ccl, interfaces);检查代理包的访问public static final String PROXY_PACKAGE = "com.sun.proxy";
  • Class<?> cl = getProxyClass0(loader, intfs);
    
    • 这个获得代理类

    •         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
                  return proxyClassCache.get(loader, interfaces);
              }
      
      • 上面是判断class字节码文件的大小的如果超出了就报错
      • return中的get方方法就是搞缓存的 太多了不想看了
  •         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});
    
    • 1、获得安全管理器
    • 2、检查新代理的权限,就是检查包名和类加载器,
    • 3、判断代理类的修饰符是否为public,不是的话就继续走
    • 4、就是设置权限,可访问
    • 5、返回一个新实例
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值