Spring初始化Ioc源码分析以及Aop原理分析(四)

Spring AOP原理

经过前面的分析,大致已经了解了Spring的原理,其中在使用的时候,有一个很重要的点就是AOP编程,什么是AOP,就不多做概述了,一句话:面向切面编程,在原有业务逻辑上,通过动态代理进行功能增强。
在Spring中主要是利用了BeanPostProcessor可以在Bean生命周期进行拦截的特性。因此主要有两步:

  • 解析xml的时候,注册aop相关的BeanPostProcessor
  • 普通Bean初始化的时候BeanPostProcessor的作用

1.1 AnnotationAwareAspectJAutoProxyCreator 的解析

在ApplicationContext.xml 中,如果要使用aop需要有这样一个标签

<beans>
    <aop:aspectj-auto />
</beans>

在前面配置文件的解析分析中,说明了针对这种自定义的标签,一定会有一个对应的NameSpaceHandler处理器。针对aop标签的处理器就是AopNamespaceHandler

public void init() {
        this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        // 这里是解析的开始处
        this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
        this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }
}

一直进入到下面这个方法

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    // 在这里就可以看到 AnnotationAwareAspectJAutoProxyCreator 这个类了
    // 这个类就是aop相关的BeanPostProcessor实现类
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }

具体是获取的就不详细分析了。

1.2 AnnotationAwareAspectJAutoProxyCreator 在运行期如何创建代理的

来看这个类的代码

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
    private List<Pattern> includePatterns;
    private AspectJAdvisorFactory aspectJAdvisorFactory;
    private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;

    public AnnotationAwareAspectJAutoProxyCreator() {
    }

    public void setIncludePatterns(List<String> patterns) {
    }

    public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
    }

    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }

    protected List<Advisor> findCandidateAdvisors() {
    }

    protected boolean isInfrastructureClass(Class<?> beanClass) {
    }

    protected boolean isEligibleAspectBean(String beanName) {
    }

    private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {
        public BeanFactoryAspectJAdvisorsBuilderAdapter(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
            super(beanFactory, advisorFactory);
        }

        protected boolean isEligibleBean(String beanName) {
            return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName);
        }
    }
}

在这个类的方法中,并没有典型的几个切面方法,所以需要去看它的父类,来看一下这个类的继承关系
《Spring初始化Ioc源码分析以及Aop原理分析(四)》
可以看到AnnotationAwareAspectJAutoProxyCreator 中实现了BeanPostProcessor 和 InstantionAwareBeanPostProcessor ,而且基类是AbstarctAutoProxyCreator 类,在这个类中就可以看到我们想要看的东西

// bean实例化前执行的方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        Object cacheKey = this.getCacheKey(beanClass, beanName);
        if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }

            if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        if (beanName != null) {
            TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
            if (targetSource != null) {
                this.targetSourcedBeans.add(beanName);
                Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
                Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            }
        }

        return null;
    }
    // 实例化后注入属性前 执行
    public boolean postProcessAfterInstantiation(Object bean, String beanName) {
        return true;
    }
    // 上面的方法执行后,再执行这个方法
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
        return pvs;
    }
    // 注入属性后,bean执行初始化方法前,执行。
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }
    // 注入属性后,bean执行初始化方法后,执行。
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean != null) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }

        return bean;
    }

观察上面几个切面方法,可以看到只有两个方法有实质性意义:

  • bean实例化前执行的方法
    public Object postProcessBeforeInstantiation
  • 注入属性后,bean执行初始化方法后,再执行。
    public Object postProcessAfterInitialization

1.2.1 postProcessBeforeInstantiation 方法解析

第一个方法作用是判断当前Bean可不可以被代理。

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    // 创造一个缓存key
        Object cacheKey = this.getCacheKey(beanClass, beanName);
        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        // 是否已经包含这个cacheKey,即是否已经包含当前Bean了
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
  /* 这个判断非常重要,第一个方法表示 是否是advice | PointCut | Advisor 等aop基类,是的话,先把这个类存储到advisedBeans中,标志位false,即不能代理。 第二个方法,是通过shouldSkip()方法,把当前Bean的所有通知和切面结合成Advisor通知器。最后判断是否应该跳过。 */
            if (this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }
// 这里是问是否要自定义目标代理的,通常是返回null,所以,虽然下面代码也有创建代理
// 但通常不会执行,实际创建代理还是在postProcessAfterInitialization中
        TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }

            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        } else {
            return null;
        }
    }

1.2.2 postProcessAfterInitialization 方法解析

第二个方法就是根据第一个方法,实际生成代理类的地方

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean != null) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {                // 继续进入方法中,这个是核心方法。
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        } 
// 这里就是根据第一个取值去判断是否应该去获取代理类
// 很明显,如果前面存了false的就会直接返回。
else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        // 这里又出现了这两个方法,是为了保险起见的重复判断
        // 在shouldSkip方法中,虽然也对切面进行了获取,但只是为了判断,
        // 下面的getAdvicesAndAdvisorsForBean方法才会返回切面
        else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
        // 这个方法中,会将所有的通知器(切面) Advisors 返回到specificInterceptors 中。 
            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                // 创建代理
                Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            } else {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    }

上面的方法,就是经过一系列判断,最后到达最后两个步骤:

  • 获取当前Bean相关的通知器(通知和切点的结合,也可以叫切面)
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 继续调用findEligibleAdvisors方法,
        List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
        // 根据获取到的通知器集合,判断是返回null,还是集合。
        return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
    }
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 这是获取所有通知器的方法
        List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
        // 这是过滤出当前Bean应该应用的通知器的方法
        List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        this.extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

由于通常使用的aop都是由注解来完成的,因此findCandidateAdvisors()方法应该也查看 AnnotationAwareAspectJAutoProxyCreator 类中的

protected List<Advisor> findCandidateAdvisors() {
//调用父类的方法,作用是获取配置文件中的 通知
        List<Advisor> advisors = super.findCandidateAdvisors();
        if (this.aspectJAdvisorsBuilder != null) {
   // this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 这个方法是根据注解了@Aspect的类去获取通知器
           advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }
  • 根据获取的通知器,创建代理
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
        }

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);
        if (!proxyFactory.isProxyTargetClass()) {
            if (this.shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            } else {
                this.evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

        Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
        // 把通知器放到生成代理的工厂中
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        this.customizeProxyFactory(proxyFactory);
        proxyFactory.setFrozen(this.freezeProxy);
        if (this.advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
// 生成代理,里面会判断是采用JDK动态代理,还是cglib动态代理。
        return proxyFactory.getProxy(this.getProxyClassLoader());
    }

总结:
aop的应用主要是利用了BeanPostProcessor的在Bean生命周期有前置和后置方法的特性,来在Bean初始化完成后,进行动态代理,使运行时使用的类,已经是被动态代理的代理类。
主要步骤:

  1. 通过AopNamespaceHandler 注册实现了BeanPostProcessor接口的AnnotationAwareAspectJAutoProxyCreator 类。
  2. 在容器中的Bean实例化的时候,根据实例化前的前置方法 postProcessBeforeInstantiation 判断是否可以被代理。
  3. 根据初始化后的后置方法 postProcessAfterInitialization 进行实际的代理创建,其中包括两步:获取当前Bean的所有切面(通知器)集合; 根据条件选择jdk动态代理或者cglib进行动态代理。

Spring中的事务,就是利用了AOP代理来实现的,Spring扩展的大部分功能都是通过AOP代理实现的。

ps:终于磕磕碰碰的写到了这里,这个系列就结束了。

    原文作者:AOP
    原文地址: https://blog.csdn.net/Mooneal/article/details/80953988
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞