Spring系列之Spring框架和SpringAOP集成过程分析

Posted 木叶之荣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring系列之Spring框架和SpringAOP集成过程分析相关的知识,希望对你有一定的参考价值。

转载请注明出处:https://blog.csdn.net/zknxx/article/details/80725173
我们在这篇文章中来分析一下AnnotationAwareAspectJAutoProxyCreator这个类,看这个类的名字我们大概可以知道它主要是为AspectJ注解提供服务的类。这个类不得了了是一个相当厉害的类,在这个类中可以识别应用中的所有切面类,为目标类找寻合适的Advisor,将目标类变为代理类等功能。话不多说了,下面我们来简单的分析一下这个类。
首先我们来看一下这个类的类图:

从上面的图中我们可以看到AnnotationAwareAspectJAutoProxyCreator这个类间接实现了BeanFactoryAware、BeanClassLoaderAware、Ordered、BeanPostProcessor接口。如果之前没有了解过Spring Bean的生命周期(或者是Spring开放的对Bean进行修改的扩展接口)的话,请点击这里查看(Spring Bean的生命周期小析(一)Spring Bean的生命周期小析(二))这里就不再多说了。上面提到的接口的实现类大多是在AbstractAutoProxyCreator这个类中实现的。Spring提供的这些关于Bean的扩展接口大大方便了我们在Bean的创建过程中对Bean进行一些修改的操作。我们按照顺序来看看AnnotationAwareAspectJAutoProxyCreator这个关系链上对这些接口的实现。

AbstractAdvisorAutoProxyCreator#setBeanFactory

    @Override
    public void setBeanFactory(BeanFactory beanFactory) 
        //掉用父类的setBeanFactory 这里只是一个简单的赋值
        super.setBeanFactory(beanFactory);
        //如果BeanFactory不是ConfigurableListableBeanFactory类型的 抛出异常
        if (!(beanFactory instanceof ConfigurableListableBeanFactory)) 
            throw new IllegalArgumentException(
                    "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
        
        //初始化BeanFactory
        initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
    
    //这个方法在AnnotationAwareAspectJAutoProxyCreator这个类型中
    @Override
    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) 
        //调用父类的initBeanFactory 执行的内容如下:
        //this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
        //创建BeanFactoryAdvisorRetrievalHelperAdapter 从BeanFactory中获取Advisor类型的Bean
        super.initBeanFactory(beanFactory);
        if (this.aspectJAdvisorFactory == null) 
            //创建ReflectiveAspectJAdvisorFactory 相当重要的一个类
            this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
        
        //创建BeanFactoryAspectJAdvisorsBuilderAdapter 相当重要的一个类
        //为目标类型创建对应的Advisor的类
        this.aspectJAdvisorsBuilder =
                new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
    

AbstractAutoProxyCreator#postProcessBeforeInstantiation

这个方法可以让我们在Bean被Spring容器实例化之前提前创建Bean,如果这个方法返回的值不是null,那就中断其他类对这个接口的实现,直接返回这个创建的Bean。在AbstractAutoProxyCreator中其源码如下:

    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException 
        //得到一个缓存的key 实现是:如果是beanClass是FactoryBean类型,则在beanName前面加&
        Object cacheKey = getCacheKey(beanClass, beanName);
        //如果目标Bean的集合中包这个beanName的话 则跳过
        if (beanName == null || !this.targetSourcedBeans.contains(beanName)) 
            if (this.advisedBeans.containsKey(cacheKey)) 
                return null;
            
            //isInfrastructureClass 判断是不是负责AOP基础建设的Bean,如果是AOP基础建设的Bean不能在这里被创建代理对象
            //那么什么样的Bean是AOP的基础建设Bean呢?Advice、Pointcut、Advisor、AopInfrastructureBean类型的Bean
            //以及含有Aspect注解的Bean
            //shouldSkip这个方法是判断这个类型的Bean能不能被跳过,如果可以跳过,那么就不提前创建这个类
            //这个类我们在下面详细分析
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) 
                //缓存这个beanClass
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            
        
        / Create proxy here if we have a custom TargetSource.
        // Suppresses unnecessary default instantiation of the target bean:
        // The TargetSource will handle target instances in a custom fashion.
        if (beanName != null) 
            //一般我们都是不配置TargetSourceCreator 下面的步骤我们先跳过 在后面我们还会继续分析下面的内容的
            TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
            if (targetSource != null) 
                this.targetSourcedBeans.add(beanName);
                Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
                Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            
        

AspectJAwareAdvisorAutoProxyCreator#shouldSkip

    protected boolean shouldSkip(Class<?> beanClass, String beanName) 
        // TODO: Consider optimization by caching the list of the aspect names
        //我们重点看到是findCandidateAdvisors这个方法的内容
        //查找所有可选择对的Advisor 并且或进行缓存
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        for (Advisor advisor : candidateAdvisors) 
            if (advisor instanceof AspectJPointcutAdvisor) 
                //如果AbstractAspectJAdvice类型的Advice中有aspectName和beanName相等则跳过
                if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) 
                    return true;
                
            
        
        //父类直接返回一个false
        return super.shouldSkip(beanClass, beanName);
    
AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
    @Override
    protected List<Advisor> findCandidateAdvisors() 
        // Add all the Spring advisors found according to superclass rules.
        // 同样是先调用父类的findCandidateAdvisors
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        //构建所有切面Bean中的Advisor
        //很重要的一个方法 下面分析
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    
    // AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
    protected List<Advisor> findCandidateAdvisors() 
        //这个advisorRetrievalHelper 就是我们在 initBeanFactory中创建的BeanFactoryAdvisorRetrievalHelper
        return this.advisorRetrievalHelper.findAdvisorBeans();
    

    // BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
    //这个方法的内容是从Spring容器中获取Advisor类型的Bean
    public List<Advisor> findAdvisorBeans() 
        // Determine list of advisor bean names, if not cached already.
        String[] advisorNames = null;
        synchronized (this) 
            //先看看之前是不是缓存过
            advisorNames = this.cachedAdvisorBeanNames;
            if (advisorNames == null) 
                // Do not initialize FactoryBeans here: We need to leave all regular beans
                // uninitialized to let the auto-proxy creator apply to them!
                //上面的注释说的很清楚 这里不会初始化FactoryBean 为什么会这样说呢?因为提前导致FactoryBean类型的Bean被创建的话是会有问题的
                //从BeanFactory中获取所有的Advisor类型的Bean
                advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Advisor.class, true, false);
                //这里进行赋值缓存
                this.cachedAdvisorBeanNames = advisorNames;
            
        
        //如果没有Advisor类型的Bean的话 直接返回
        //如果你有特殊需求的话 可以实现Advisor接口,并向Spring容器中注入对应的Bean
        if (advisorNames.length == 0) 
            return new LinkedList<Advisor>();
        
        //这里是默认创建了一个 Advisor类型的集合 
        List<Advisor> advisors = new LinkedList<Advisor>();
        for (String name : advisorNames) 
            //这里默认返回的是true
            if (isEligibleBean(name)) 
                //如果是正在创建中的Bean 则跳过
                if (this.beanFactory.isCurrentlyInCreation(name)) 
                    if (logger.isDebugEnabled()) 
                        logger.debug("Skipping currently created advisor '" + name + "'");
                    
                
                else 
                    try 
                        //从BeanFactory中获取对应的Bean 这里如果Bean还没创建 会导致Bean创建
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                    
                    catch (BeanCreationException ex) 
                    //异常处理 略
                    
                
            
        
        return advisors;
    

下面我们来看看BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors中的这个方法,从名字我们就可以看出来这是一个从BeanFactory中构建Advisor的方法。

    public List<Advisor> buildAspectJAdvisors() 
        //所有的切面的名字 这里的处理逻辑和上面的是一样的 获取到所有的切面BeanName之后缓存起来 volatile类型的
        List<String> aspectNames = this.aspectBeanNames;
        if (aspectNames == null) 
            synchronized (this) 
                //这里又赋值了一次  看着这个逻辑是不是和某个单例的写法很像啊?
                aspectNames = this.aspectBeanNames;
                if (aspectNames == null) 
                    List<Advisor> advisors = new LinkedList<Advisor>();
                    aspectNames = new LinkedList<String>();
                    //这里是从BeanFactory中获取所有的Bean
                    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Object.class, true, false);
                    for (String beanName : beanNames) 
                        //这里默认都是true
                        if (!isEligibleBean(beanName)) 
                            continue;
                        
                        // We must be careful not to instantiate beans eagerly as in this case they
                        // would be cached by the Spring container but would not have been weaved.
                        //注意看上面这个注释的内容:在这个场景下我们获取BeanClass的时候必须要小心处理,以免会提前初始化
                        //Bean,这些Bean在初始化之后会被Spring容器缓存起来,但是这些Bean可能还没有被织入。
                        Class<?> beanType = this.beanFactory.getType(beanName);
                        if (beanType == null) 
                            continue;
                        
                        //判断上面获取到的BeanClass是否带有Aspect注解
                        if (this.advisorFactory.isAspect(beanType)) 
                            //添加到 aspectNames中
                            aspectNames.add(beanName);
                            //创建切面元数据 这部门的内容和我们之前分析大致差不多 我们就不再详细分析了
                            //请看这里: https://blog.csdn.net/zknxx/article/details/79685290
                            AspectMetadata amd = new AspectMetadata(beanType, beanName);
                            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) 
                                //注意这里放入了 BeanFactory的引用 方便后面从BeanFactory中获取切面的实例
                                MetadataAwareAspectInstanceFactory factory =
                                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                //如果是单例的 缓存起来
                                if (this.beanFactory.isSingleton(beanName)) 
                                    this.advisorsCache.put(beanName, classAdvisors);
                                
                                else 
                                    this.aspectFactoryCache.put(beanName, factory);
                                
                                advisors.addAll(classAdvisors);
                            
                            else 
                                // Per target or per this.
                                if (this.beanFactory.isSingleton(beanName)) 
                                    throw new IllegalArgumentException("Bean with name '" + beanName +
                                            "' is a singleton, but aspect instantiation model is not singleton");
                                
                                //这里使用的是 PrototypeAspectInstanceFactory
                                MetadataAwareAspectInstanceFactory factory =
                                        new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                                this.aspectFactoryCache.put(beanName, factory);
                                advisors.addAll(this.advisorFactory.getAdvisors(factory));
                            
                        
                    
                    this.aspectBeanNames = aspectNames;
                    return advisors;
                
            
        

        if (aspectNames.isEmpty()) 
            return Collections.emptyList();
        
        //下面这些就是从缓存中获取Advisor了
        List<Advisor> advisors = new LinkedList<Advisor>();
        for (String aspectName : aspectNames) 
            List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
            if (cachedAdvisors != null) 
                advisors.addAll(cachedAdvisors);
            
            else 
                MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
                advisors.addAll(this.advisorFactory.getAdvisors(factory));
            
        
        return advisors;
    

总结起来findCandidateAdvisors这个方法的内容就是从Spring容器中获取所有Advisor类型的Bean和切面中所有带有通知注解的方法并将其封装为Advisor。那么其实我们在AbstractAutoProxyCreator的postProcessBeforeInstantiation方法中就获取到了Spring容器中的所有Advisor。

AbstractAutoProxyCreator#postProcessAfterInstantiation
    //通常都是返回true
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) 
        return true;
    

AbstractAutoProxyCreator#postProcessPropertyValues

    @Override
    public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) 
        //不做处理
        return pvs;
    

AbstractAutoProxyCreator#postProcessBeforeInitialization

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) 
        //不做处理原样返回
        return bean;
    
AbstractAutoProxyCreator#postProcessAfterInitialization

这个方法需要重点分析一下了

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException 
          if (bean != null) 
            //获取缓存的key
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            //如果不是提前引用的Bean
            if (!this.earlyProxyReferences.contains(cacheKey)) 
                //如果需要的话 对传入的Bean进行包装
                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;
        
        //如果这里返回的是False的话 直接返回
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) 
            return bean;
        
        //这里又判断了一次不再多说了、、、
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) 
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        
        //getAdvicesAndAdvisorsForBean这个方法下面我们要重点说一下
        // Create proxy if we have 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;
        
        //如果不需要创建代理对象的话  这里缓存false
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    

转载请注明出处:https://blog.csdn.net/zknxx/article/details/80725173

以上是关于Spring系列之Spring框架和SpringAOP集成过程分析的主要内容,如果未能解决你的问题,请参考以下文章

SSM 框架快速整合实例--学生查询

SSH框架之Spring系列

Spring系列之Spring框架和SpringAOP集成过程分析

Spring系列之Spring框架和SpringAOP集成过程分析

框架学习系列 之Spring框架学习总结

1.spring系列之简要概述