zoukankan      html  css  js  c++  java
  • Spring AOP 之动态代理源码分析

    本文参考网址:https://www.jianshu.com/p/9bcac608c714    https://www.cnblogs.com/yaowen/p/10117893.html

    Class<?> string01 = person.getClass().getInterfaces()[0];

    使用说明,在动态代理中使用到了该方法,该方法的作用是获得对象的所有

    1. SecurityManager应用场景

       当运行未知的java程序的时候,该程序可能有恶意代码(删除粗系统文件,重启系统),位了防止运行恶意代码对系统产生影响,需要对运行的代码权限控制。这个时候就需要启动java安全管理器。

    2. Reflection.getCallerClass()此方法的调用者必须要有权限,需要什么样的权限了,

      由bootstrap class loader 加载类可以调用

      由extension calss loader 加载类可以调用

    3. 我们都知道用户路径的类加载是由application calss loader进行加载的,换句话说,用户自定义的一些类无法调用该方法。

    4. Reflection.getCallerCalss()方法调用所在的方法必须要加注解@CallerSensitive进行注解。

      这个方法的使用: 可以得到调用者的类。

      1 返回自己的类

      2. 返回调用者的类

      3. 4.5 层层上传

    5.具体的实例

    public interface HelloService {
        void sayHello();
    }
    public class HelloServiceProxy implements InvocationHandler{
        private Object target;
    
        public Object bind(Object target, Class[] interfaces) {
            this.target = target;
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result;
            System.out.println("###########这里是动态代理##########");
            //反射方法前调用
            System.out.println("调用前");
            //反射执行方法  相当于调用target.sayHelllo;
            result = method.invoke(target,args);
            //反射方法后调用.
            System.out.println("调用后");
    
            return result;
        }
    }
    public class ProxyTest {
    
        public static void main(String[] args) {
            HelloServiceProxy proxy = new HelloServiceProxy();
            HelloService service = new HelloServiceImpl();
            HelloService serviceProxy = (HelloService)proxy.bind(service, new Class[] {HelloService.class});
    
            serviceProxy.sayHello();
        }
    }

    源码分析:Proxy 类静态方法NewProxyInstance

     public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            //如果h为空,抛出空指针异常。
            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<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { //权限校验 if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } //获取参数类型是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; } }); } //传入InvocationHandler实例去构造一个代理类的实例,所有代理类都继承自Proxy,而Proxy构造方法需要InvocationHandler实例作为参数 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); } }

    从newProxyInstance 方法看出,产生代理类核心代码在getProxyClas0()

    private static Class<?> getProxyClass0(ClassLoader loader,
     2                                            Class<?>... interfaces) {
     3         if (interfaces.length > 65535) {
     4             throw new IllegalArgumentException("interface limit exceeded");
     5         }
     6 
     7         // If the proxy class defined by the given loader implementing
     8         // the given interfaces exists, this will simply return the cached copy;
     9         // otherwise, it will create the proxy class via the ProxyClassFactory
    10         //如果由实现给定接口的代理类存在,这将简单地返回缓存的副本;否则,将通过ProxyClassFactory创建代理类
    11         return proxyClassCache.get(loader, interfaces);
    12     }

    getProxyClas0通过类加载器和接口集合取缓存里边获取,如果能找到直接返回,否则就会调用ProxyClassFactory这个工厂去生成一个代理类,下面我们看下Proxy的静态内部类。

     private static final class ProxyClassFactory
      2         implements BiFunction<ClassLoader, Class<?>[], Class<?>>
      3     {
      4         // prefix for all proxy class names 代理类名称前缀
      5         private static final String proxyClassNamePrefix = "$Proxy";
      6 
      7         // next number to use for generation of unique proxy class names, 用原子类来生成代理类的序号, 保证序号唯一
      8         private static final AtomicLong nextUniqueNumber = new AtomicLong();
      9 
           //loader ,以及它代替的接口类 10 @Override 11 public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { 12 13 Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); 14 for (Class<?> intf : interfaces) { 15 /* 16 * Verify that the class loader resolves the name of this 17 * interface to the same Class object. 18 */ 19 Class<?> interfaceClass = null; 20 try { 21 interfaceClass = Class.forName(intf.getName(), false, loader); 22 } catch (ClassNotFoundException e) { 23 } 24 //intf是否可以由指定的类加载进行加载 25 if (interfaceClass != intf) { 26 throw new IllegalArgumentException( 27 intf + " is not visible from class loader"); 28 } 29 /* 30 * Verify that the Class object actually represents an 31 * interface. 32 * intf是否是一个接口 33 */ 34 if (!interfaceClass.isInterface()) { 35 throw new IllegalArgumentException( 36 interfaceClass.getName() + " is not an interface"); 37 } 38 /* 39 * Verify that this interface is not a duplicate. 40 * intf在数组中是否有重复 41 */ 42 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { 43 throw new IllegalArgumentException( 44 "repeated interface: " + interfaceClass.getName()); 45 } 46 } 47 // package to define proxy class in 生成代理类的包名 48 String proxyPkg = null; 49 // 代理类的访问标志, 默认是public final 50 int accessFlags = Modifier.PUBLIC | Modifier.FINAL; 51 52 /* 53 * Record the package of a non-public proxy interface so that the 54 * proxy class will be defined in the same package. Verify that 55 * all non-public proxy interfaces are in the same package. 56 * 验证所有非公共代理接口都在同一个包中 57 */ 58 for (Class<?> intf : interfaces) { 59 //获取接口的访问标志 60 int flags = intf.getModifiers(); 61 //如果接口的访问标志不是public, 那么生成代理类的包名和接口包名相同 62 if (!Modifier.isPublic(flags)) { 63 //生成的代理类的访问标志设置改为final 64 accessFlags = Modifier.FINAL; 65 String name = intf.getName(); 66 int n = name.lastIndexOf('.'); 67 String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); 68 if (proxyPkg == null) { 69 proxyPkg = pkg; 70 } else if (!pkg.equals(proxyPkg)) { 71 //代理类如果实现不同包的接口, 并且接口都不是public的, 那么就会在这里报错 72 throw new IllegalArgumentException( 73 "non-public interfaces from different packages"); 74 } 75 } 76 } 77 78 if (proxyPkg == null) { 79 // if no non-public proxy interfaces, use com.sun.proxy package 如果没有非公共代理接口,那生成的代理类都放到默认的包下:com.sun.proxy 80 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; 81 } 82 83 /* 84 * Choose a name for the proxy class to generate. 85 * 生成代理类的全限定名, 包名+前缀+序号, 例如:com.sun.proxy.$Proxy0 86 */ 87 long num = nextUniqueNumber.getAndIncrement(); 88 String proxyName = proxyPkg + proxyClassNamePrefix + num; 89 90 /* 91 * Generate the specified proxy class. 92 * 这里是核心, 用ProxyGenerator来生成字节码, 该类放在sun.misc包下 93 */ 94 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( 95 proxyName, interfaces, accessFlags); 96 //根据二进制文件生成相应的Class实例 97 try { 98 return defineClass0(loader, proxyName, 99 proxyClassFile, 0, proxyClassFile.length); 100 } catch (ClassFormatError e) { 101 /* 102 * A ClassFormatError here means that (barring bugs in the 103 * proxy class generation code) there was some other 104 * invalid aspect of the arguments supplied to the proxy 105 * class creation (such as virtual machine limitations 106 * exceeded). 107 */ 108 throw new IllegalArgumentException(e.toString()); 109 } 110 } 111 }
  • 相关阅读:
    遗传算法(Genetic Algorithm, GA)及MATLAB实现
    CCF CSP 201809-2 买菜
    PAT (Basic Level) Practice (中文)1008 数组元素循环右移问题 (20 分)
    PAT (Basic Level) Practice (中文)1006 换个格式输出整数 (15 分)
    PAT (Basic Level) Practice (中文)1004 成绩排名 (20 分)
    PAT (Basic Level) Practice (中文)1002 写出这个数 (20 分)
    PAT (Advanced Level) Practice 1001 A+B Format (20 分)
    BP神经网络(原理及MATLAB实现)
    问题 1676: 算法2-8~2-11:链表的基本操作
    问题 1744: 畅通工程 (并查集)
  • 原文地址:https://www.cnblogs.com/dousil/p/12859005.html
Copyright © 2011-2022 走看看