Spring AOP 代理过程分析

@EnableAspectJAutoProxy 注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    // 使用CGLIB代理
    boolean proxyTargetClass() default false;
    // 是否暴露代理对象
    boolean exposeProxy() default false;
}

在这个注解中引入AspectJAutoProxyRegistrar,它是ImportBeanDefinitionRegistrar接口的实现。
ImportBeanDefinitionRegistrar接口和ImportSelector接口是Spring中两个扩展接口,分别通过registerBeanDefinitions方法和selectImports方法向容器注入Bean。
AspectJAutoProxyRegistrar的registerBeanDefinitions方法:

public void registerBeanDefinitions(
        AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    // 注册AnnotationAwareAspectJAutoProxyCreator 
    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
    // proxyTargetClass:true强制使用CGLIB代理  
    if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
    }
    // 是否暴露代理对象 
    if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
        AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
    }
}

1、进入AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法会发现这个方法将一个类AnnotationAwareAspectJAutoProxyCreator注册到了容器中。
2、proxyTargetClass=true则强制使用CGLIB代理,否则会根据目标类是否实现了接口,自动选择是JDK代理或者是CGLIB代理。
3、有时候目标对象内部的自我调用无法实施切面中增强exposeProxy=true会将代理对象暴漏到AopContext中,此时使用AopContext.currentProxy即可。

AOP切入点

AnnotationAwareAspectJAutoProxyCreator类的继承关系为:

BeanPostProcessor
|
SmartInstantiationAwareB
|
AbstractAutoProxyCreator
|
AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator是BeanPostProcessor接口的实现。
BeanPostProcessor这个接口Spring中一个特殊且重要的接口,会在容器实例化Bean的时候调用,调用不止一次,比如会在实例化前,实例化后,属性填充后等等适合的时机调用BeanPostProcessor的实现。具体参见spring容器加载分析 一容器构造

大致梳理下Bean的实例化过程:

在AbstractAutowireCapableBeanFactory类中有具体的Bean实例化方法doCreateBean:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
    1: 实例化Bean
    instanceWrapper = createBeanInstance(beanName, mbd, args); 
    2: 是否需要提早曝光:单例&允许循环依赖&当前bean增在创建中,检查循环依赖
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                        isSingletonCurrentlyInCreation(beanName));
    3: 对bean的各种属性进行填充,有可能依赖其他bean,递归初始化   step4.2.3
    4: 调用初始化方法init-method、此处也有机会返回Bean的代理对象
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    5: 解决循环依赖
    return exposedObject;
}

进入initializeBean方法:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    1:如果Bean有InitMethod开始调用
    invokeInitMethods(beanName, wrappedBean, mbd);
    2: 调用BeanPostProcessors的postProcessBeforeInitialization方法
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    3: 调用BeanPostProcessors的postProcessAfterInitialization方法
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    // 如果启用了AOP此处应该返回了代理对象,也就是说原来初始化的bean被替换了。
    return wrappedBean;
}

AOP生成代理的切入点就在applyBeanPostProcessorsAfterInitialization方法中了,遍历BeanPostProcessor列表然后依次调用postProcessAfterInitialization方法,AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法中正好返回了Bean的代理对象,则代理对象在doCreateBean方法中替换掉了原生的Bean实例。

代理对象生成和切面织入过程

postProcessAfterInitialization方法的实现:

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 不存在代理,生成
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 已处理过
    if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    //判断给定的BEAN是否是一个基础设施类  ,基础设施类不应代理或者配置了指定的BEAN不需要代理
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }
    // 如果目标类存在advice则创建代理.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

只有存在advice(增强)的Bean才会创建代理,getAdvicesAndAdvisorsForBean就是获取绑定到Bean上的advice列表,如果列表为空则不创建代理。

获取advice列表在类AnnotationAwareAspectJAutoProxyCreator中。

protected List<Advisor> findCandidateAdvisors() {
    // 调用父类的方法去查找Advisors,查找所有实现了org.springframework.aop.Advisor接口的BEAN
    // 主要是为了不遗漏XML配置的advisors
    List<Advisor> advisors = super.findCandidateAdvisors();
    // AspectJ注解的Advisor
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    return advisors;
}

第一步先获取实现了Advisor接口的Bean,使用BeanFactoryUtils.beanNamesForTypeIncludingAncestors方法。
第二步获取有@Aspect注解的Bean,委托给了BeanFactoryAspectJAdvisorsBuilder类,解析方法buildAspectJAdvisors()处理过程如下:

1:获取所有的beanNames,再由beanFactory.getType(beanName)获取Bean的class列表
2:判断是否包含@Aspect注解
3:解析成Advisor列表
4:使用AopUtils.findAdvisorsThatCanApply检查Advisor与Bean是否匹配,过滤掉不匹配的Advisor。

如果Advisor列表不为空则进入代理创建逻辑,

protected Object createProxy(
        Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    ProxyFactory proxyFactory = new ProxyFactory();
    //拷贝当前类中的相关属性
    proxyFactory.copyFrom(this);
    //判定给定的bean是否代理Class
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }else {
            // 评估解析代理的接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 添加Advisors
    proxyFactory.addAdvisors(advisors);
    // 设置目标类
    proxyFactory.setTargetSource(targetSource);
    // 定制代理
    customizeProxyFactory(proxyFactory);
    // 设置是否冻结,默认为false即代理设置后不允许修改代理的配置
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    return proxyFactory.getProxy(getProxyClassLoader());
}

ProxyFactory中委托DefaultAopProxyFactory类来确定Bean的代理类型

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 对生成代理策略进行优化||强制使用CGLIB来实现代理||不适用接口代理
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        // 目标类为接口,JDK代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // CGLIB代理
        return new ObjenesisCglibAopProxy(config);
    } else {
        // JDK代理
        return new JdkDynamicAopProxy(config);
    }
}

此时已经确定了Bean是使用JDK代理还是使用CGLIB代理,JDK代理使用
JdkDynamicAopProxy来生成代理类、CGLIB代理使用ObjenesisCglibAopProxy来生成代理类。
ObjenesisCglibAopProxy代理类的生成过程:

public Object getProxy(ClassLoader classLoader) {
    try {
        // 目标对象
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
        Class<?> proxySuperClass = rootClass;
        // 目标对象是否是CGLIB的代理对象
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }
        // 验证类,主要是验证final方法
        validateClassIfNecessary(proxySuperClass, classLoader);
        // CGLIB的增强器
        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));
        // 获取类的回调列表,都是MethodInterceptor的实例
        // 最主要的DynamicAdvisedInterceptor,这个就是动态织入增强的拦截器
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);
        return createProxyClassAndInstance(enhancer, callbacks);
    }
}

这个方法就是创建代理的核心方法,主要是获取目标对象,获取类的回调列表,这个回调列表都是MethodInterceptor的实例,可以看成是方法的拦截器链。其中最主要的是DynamicAdvisedInterceptor,这个Interceptor为Bean的切点方法进行Advisor动态织入。

// proxy 代理对象 、method 目标类方法 、args 方法参数、 methodProxy 每个被代理的方法都对应一个MethodProxy对象
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Class<?> targetClass = null;
    Object target = null;
    try {
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }
        // 目标对象
        target = getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }
        // 获取拦截器链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        // 如果没有拦截器链,则直接调用目标类的方法
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 返回目标对象的调用结果
            retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
            // 构造CglibMethodInvocation,递归调用拦截器链
            retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        // 返回实施增强之后的调用结果
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    }
}

intercept就是拦截代理类的方法,匹配切入点,如果方法可以切入则根据切入逻辑依次执行增强逻辑,如果不匹配切入点则直接执行目标类的方法,切入点匹配逻辑在DefaultAdvisorChainFactory类中实现。

码字不易,转载请保留原文连接[https://www.jianshu.com/p/f504afb066f9)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342