Spring AOP分析(3) -- CglibAopProxy实现AOP

上文探讨了应用JDK动态代理实现Spring AOP功能的方式,下面将继续探讨Spring AOP功能的另外一种实现方式 -- CGLIB。

首先,来看看类名CglibAopProxy,该类实现了两个接口:一个是AopProxy接口,一个是Serializable接口。直接忽略Serializable接口,AopProxy接口中只定义了两个同名方法getProxy。如下所示:

class CglibAopProxy implements AopProxy, Serializable

类中有一个非常重要的属性advised,该属性在JdkDynamicAopProxy中也存在,主要用于配置代理信息,是一个非常重要的属性,如下

protected final AdvisedSupport advised;

属性为final类型,可以被子类继承,一旦赋值后便不能改变。在CglibAopProxy中,advised在构造器中被赋值,后续不可更改:

    public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
        Assert.notNull(config, "AdvisedSupport must not be null");
        if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
            throw new AopConfigException("No advisors and no TargetSource specified");
        }
        this.advised = config;
        this.advisedDispatcher = new AdvisedDispatcher(this.advised);
    }

跟JdkDynamicAopProxy一样,实现了AopProxy接口,实现了getProxy()方法,如下:

    @Override
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
        }

        try {
            Class<?> rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

            Class<?> proxySuperClass = rootClass;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class<?> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }

            // Validate the class, writing log messages as necessary.
            validateClassIfNecessary(proxySuperClass, classLoader);

            // Configure CGLIB Enhancer...
            Enhancer enhancer = createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader &&
                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // fixedInterceptorMap only populated at this point, after getCallbacks call above
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);

            // Generate the proxy class and create a proxy instance.
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        catch (CodeGenerationException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                    this.advised.getTargetClass() + "]: " +
                    "Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (IllegalArgumentException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                    this.advised.getTargetClass() + "]: " +
                    "Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (Throwable ex) {
            // TargetSource.getTarget() failed
            throw new AopConfigException("Unexpected AOP exception", ex);
        }
    }

在创建代理过程中需要判断被代理类是否已经进行过验证,若没有验证过则执行验证。验证方法如下:

    private void doValidateClass(Class<?> proxySuperClass, ClassLoader proxyClassLoader, Set<Class<?>> ifcs) {
        if (proxySuperClass != Object.class) {
            Method[] methods = proxySuperClass.getDeclaredMethods();
            for (Method method : methods) {
                int mod = method.getModifiers();
                if (!Modifier.isStatic(mod)) {
                    if (Modifier.isFinal(mod)) {
                        if (implementsInterface(method, ifcs)) {
                            logger.warn("Unable to proxy interface-implementing method [" + method + "] because " +
                                    "it is marked as final: Consider using interface-based JDK proxies instead!");
                        }
                        logger.info("Final method [" + method + "] cannot get proxied via CGLIB: " +
                                "Calls to this method will NOT be routed to the target instance and " +
                                "might lead to NPEs against uninitialized fields in the proxy instance.");
                    }
                    else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && !Modifier.isPrivate(mod) &&
                            proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
                        logger.info("Method [" + method + "] is package-visible across different ClassLoaders " +
                                "and cannot get proxied via CGLIB: Declare this method as public or protected " +
                                "if you need to support invocations through the proxy.");
                    }
                }
            }
            doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader, ifcs);
        }
    }

接着配置CGLIB加强createEnhancer(),最后创建代理类生成代理实例createProxyClassAndInstance(enhancer, callbacks)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏开发之途

Android 解析RecyclerView(2)——带顶部View和底部View的RecyclerView

2515
来自专栏编程之路

羊皮书APP(Android版)开发系列(十)Android开发常用工具类

621
来自专栏Android干货

Android项目实战(三十七):Activity管理及BaseActivity的实现

4456
来自专栏吴小龙同學

Drawable /Bitmap、String/InputStream、Bitmap/byte[]互转

Drawable互转Bitmap Drawable转Bitmap 1 2 3 4Resources res = getResources(); Drawable...

3236
来自专栏Java与Android技术栈

用kotlin打造简化版本的ButterKnife

大名鼎鼎的 ButterKnife 库相信很多 android 开发者都听过,在 Github 上star的数目已经快15k了,而且很多知名的app都在使用。

973
来自专栏10km的专栏

jface databinding:label provider 实现多列表格(Table)数据绑定的两个途径

显示需求 如下图,希望将一组拥有两个字段的表与两列的table绑定在一起,实现自动显示。 ? 在jface viewer中label provide...

18810
来自专栏Android Note

Android RecyclerView添加搜索过滤器

1313
来自专栏云端漫步

go设计模式之建造者模式

func NewBuilder(build Builder) *Director {

703
来自专栏开发之途

RxJava2 入门详细笔记(2)

通过一定逻辑来过滤被观察者发送的事件,如果返回 true 则会发送事件,否则不会发送

511
来自专栏技术小黑屋

关于获取当前Activity的一些思考

在Android开发过程中,我们有时候需要获取当前的Activity实例,比如弹出Dialog操作,必须要用到这个。关于如何实现由很多种思路,这其中有的简单,有...

703

扫码关注云+社区