【java设计模式】之 代理(Proxy)模式(下)

接上一篇代理(Proxy)模式,看下proxy内部到底做了什么处理。通过上篇的代码debug,如图

p

发现这里调用proxy发现如下图中的$Proxy0和$Proxy1代理类,如何来的呢?先回顾一些知识:

类的完整生命周期如图:

一般类的完整生命周期从源文件开始,然后通过javac编译成字节码文件,然后通过类加载机制在元空间(1.7之前为方法区)生成class对象,然后new出实例化对象在堆中,之后通过可达性分析判断类是否还在被引用,没有引用在被垃圾回收GC回收。完整的生命周期。为啥在动态代理中谈到这个类的生命周期,其实所谓的$Proxy0和$Proxy1变量的生成就是跳过了源文件的编译直接从内存中生成的字节码。

          接下来我们去看看源码,里面到底是如何在内存中生成字节码文件的。首先看到之前的getProxyInstance()方法:

进入看看源码:

 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.  
         */
        //******动态代理的核心方法
        //*******JVM直接在内存中生成字节码文件并通过类加载机制得到class对象,对比类的生命周期
        Class<?> cl = getProxyClass0(loader, intfs);   

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //**********通过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);
        }
    }

 注解加入了//***的注解,核心代码还是getProxyClass0()方法。继续往里深入,

private static Class<?> getProxyClass0(ClassLoader loader,
                                       Class<?>... interfaces) {
    return proxyClassCache.get(loader, interfaces);   //继续往下
}

进入get()方法:

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

//***************************如果从缓存中没有拿到代理类,就去生成代理类******************************
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));

}

继续深入apply():真正的核心到了。

// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";  //前缀
 @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);//****拿到接口的class
            } 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
        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.
         */
        for (Class<?> intf : interfaces) {     //判断接口里面是不是加了public修饰符
            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();     
        String proxyName = proxyPkg + proxyClassNamePrefix + num;  //为什么会出现动态代理类$Proxy0和$Proxy1

        /*
         * Generate the specified proxy class.
         */
        //获取到代理类的字节码(内存中直接生成class文件)
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags);
        try {
         //把字节码,类名,类加载器丢进去拿到class对象(对应类周期的两步骤)defineClass0是一个native方法
            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());
        }
    }
}

内存中代理类的内部生成就到这里了。

之后对生成的代理类进行反编译工具,看到代理类都是Proxy的子类,代理类都要继承Porxy以及实现指定的接口。重写的方法里面调用相关业务方法的时候,调用this.h.invoke(),h->>InvocationHandler,所以就是调用动态代理类PassionProxyCompany中的invoke方法(通过动态代理对象对方法进行增强)。

动态代理类的生成核心代码基本如上了,搞清楚一个问题看源码的确不容易。继续加油把。。。。

发布了68 篇原创文章 · 获赞 9 · 访问量 7452

猜你喜欢

转载自blog.csdn.net/u013025649/article/details/103453971