Spring 学习笔记Java&Spring基础技术

Spring AOP 注解配置 源码学习

2018-02-07  本文已影响18人  jwfy

上篇Spring AOP学习中已经基本介绍了AOP是如何使用的,本文章来说说AOP注解方法的源码细节
先提几个问题,在接下来的源码学习中发现答案

具体的demo可以看Spring AOP学习#注解

XML配置解析

AOP的配置最简单的方法就是在xml中加入<aop:aspectj-autoproxy />,应该很清楚spring是选择什么命名空间去解析了,直接定位到AopNamespaceHandler 类,而且定位的是AspectJAutoProxyBeanDefinitionParser解析器,如果这点有什么疑问的话,最好是再看看spring xml的bean提取 源码学习,看完就懂了为什么会直接定位到该解析器

public class AopNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        // AspectJAutoProxyBeanDefinitionParser 是我们这次关注的类
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }
}

AspectJAutoProxyBeanDefinitionParser 类

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
    
    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
      // 可以生成AnnotationAwareAspectJAutoProxyCreator类的beandefinition
      // 并注册到IOC容器中
        extendBeanDefinition(element, parserContext);
        // 扩展该bean的属性信息
        return null;
    }

    private void extendBeanDefinition(Element element, ParserContext parserContext) {
        BeanDefinition beanDef =
                parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
      // 该bean其实就是上面所说的AnnotationAwareAspectJAutoProxyCreator的beandefinition
        if (element.hasChildNodes()) {
            addIncludePatterns(element, parserContext, beanDef);
            // 如果包含了子节点可以添加额外的includePattern
        }
    }

    private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
        ManagedList<TypedStringValue> includePatterns = new ManagedList<TypedStringValue>();
        NodeList childNodes = element.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node node = childNodes.item(i);
            if (node instanceof Element) {
                Element includeElement = (Element) node;
                TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
                // 获取子属性key为name的值
                valueHolder.setSource(parserContext.extractSource(includeElement));
                includePatterns.add(valueHolder);
            }
        }
        if (!includePatterns.isEmpty()) {
            includePatterns.setSource(parserContext.extractSource(element));
            beanDef.getPropertyValues().add("includePatterns", includePatterns);
            // 给该beandefinition赋属性值,includePatterns
        }
    }
}

如上述代码中的AnnotationAwareAspectJAutoProxyCreator类创建中,如果跳进去能够看到还可以为该类设置proxy-target-classexpose-proxy两个boolean属性值。
也可以设置子属性值name,例如下面的设置

<aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="true">
   <aop:include name="******" />
</aop:aspectj-autoproxy>

这样就清楚了这个xml配置的原理是如何,其实就是新添加了一个beandefinition而已。

Aspect 扫描和实例化

spring正常的注册的bean,如果没有加@Aspect注解也是没有用的,那么就来学习下是在什么时候被扫描到,以及后续的操作是什么。

如果大概看了AnnotationAwareAspectJAutoProxyCreator类的相关内容,可以知道AOP所有的aspect以及pointCut都存储在该对象中,所以扫描所有的注解@Aspect类,肯定是在AnnotationAwareAspectJAutoProxyCreator类的实例化之后

在refresh()代码中,在实例化具体的bean之前,已经完成了spring层面的bean实例


image.png

在接下来对org.springframework.context.event.internalEventListenerProcessor对象实例化的过程中会完成对@aspect类的扫描操作,并把相关信息注入到上图圈住的AnnotationAwareAspectJAutoProxyCreator类中。

随着代码调试到AbstractAutoProxyCreator文件

AbstractAutoProxyCreator 类

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {  
   Object cacheKey = getCacheKey(beanClass, beanName);
   // 从当前的cache容器获取到bean的name
    if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
            // 该advisedBeans已经包含了该key,则直接退出不考虑
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
           // 该bean不符合所有获取到的切面,设置为false
           // shouldSkip方法看下面的代码
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

   // 所有的注解信息已经获取到了
    // 具体通过代理类生成一个对象信息
    if (beanName != null) {
        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);
            // 利用ProxyFactory 生成一个新的对象
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }
    }

    return null;
}

AspectJAwareAdvisorAutoProxyCreator 类

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 获取所有的advisor,也就是PointCut,具体细节可看下面的函数执行过程代码
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor) {
            if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
                return true;
            }
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

BeanFactoryAdvisorRetrievalHelper 类

这个类是AnnotationAwareAspectJAutoProxyCreator的一个对象

    public List<Advisor> findAdvisorBeans() {
        String[] advisorNames = null;
        synchronized (this) {
            advisorNames = this.cachedAdvisorBeanNames;
            if (advisorNames == null) {
              // 还没准备好,首次进入该函数时,为null
                advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Advisor.class, true, false);
               // 获取到IOC容器中,所有类的类型是Advisor.class的
               // 当然就我们当前的demo而言肯定是没有的,只有加上了Advisor.class注解的类
               // 会继续进入到**buildAspectJAdvisors函数**中去获取到注解为Advisor.class的类
                this.cachedAdvisorBeanNames = advisorNames;
            }
        }
        if (advisorNames.length == 0) {
            return new LinkedList<Advisor>();
        }

        List<Advisor> advisors = new LinkedList<Advisor>();
        for (String name : advisorNames) {
            if (isEligibleBean(name)) {
                if (this.beanFactory.isCurrentlyInCreation(name)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipping currently created advisor '" + name + "'");
                    }
                }
                else {
                    try {
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                    }
                    catch (BeanCreationException ex) {
                        Throwable rootCause = ex.getMostSpecificCause();
                        if (rootCause instanceof BeanCurrentlyInCreationException) {
                            BeanCreationException bce = (BeanCreationException) rootCause;
                            if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Skipping advisor '" + name +
                                            "' with dependency on currently created bean: " + ex.getMessage());
                                }
                                // Ignore: indicates a reference back to the bean we're trying to advise.
                                // We want to find advisors other than the currently created bean itself.
                                continue;
                            }
                        }
                        throw ex;
                    }
                }
            }
        }
        return advisors;
    }
public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;

    if (aspectNames == null) {
       // 第一次进入,确实为null
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            // spring中为了确保线程安全,存在大量的类似double-check的代码
            if (aspectNames == null) {
                List<Advisor> advisors = new LinkedList<Advisor>();
                aspectNames = new LinkedList<String>();
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                // 获取IOC所有类型为Object的类名称(肯定包含了注解@Aspect的相关类)
                for (String beanName : beanNames) {
                    if (!isEligibleBean(beanName)) {
                       // 类名和includePatterns正则匹配不通过,则跳过,起到一个过滤的作用
                       // 匹配的是类似于com.demo.*这样的类名称
                       // 和上面说的<aop:include name="******" />相关联
                        continue;
                    }
                    
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                       // 获取其类型,如果为null,无效,跳过
                        continue;
                    }
                    if (this.advisorFactory.isAspect(beanType)) {
                       // 注解包含了@Aspect 并且没有被AspectJ编译(字段以ajc$开头)的类
                        aspectNames.add(beanName);
                        // 本demo的beanName就是animalAop
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            // 获取该类所有的方法,例如@Before、@After等
                            // 取到该类所有的方法,按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 的顺序排序
                            // 依次遍历,如果发现了上述的注解,则保存pointCut到一个容器中
                            
                            // 获取该类所有的共有方法,如果符合要求,也保存到容器中,最后返回到List中
                            
                            if (this.beanFactory.isSingleton(beanName)) {
                                this.advisorsCache.put(beanName, classAdvisors);
                                // 如果是单例,则保存到cache共,否则保存到工厂cache中
                            }
                            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");
                            }
                            MetadataAwareAspectInstanceFactory factory =
                                    new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                            this.aspectFactoryCache.put(beanName, factory);
                            advisors.addAll(this.advisorFactory.getAdvisors(factory));
                        }
                    }
                }
                // 这里给aspectNames 赋值
                // 需要注意到一旦赋值了,就不会为空,则不会再去扫描所有的bean,得到全部的AOP信息
                this.aspectBeanNames = aspectNames;
                return advisors;
            }
        }
    }
    
    // 能运行到这里的肯定是第二次执行,获取到需要的AOP的pointCut信息
    if (aspectNames.isEmpty()) {
        return Collections.emptyList();
    }
    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;
}

最后实例化代理对象AnimalImpl对象,经过调试来到了


image.png

AbstractAutoProxyCreator 文件

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;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 得到相关的advice
    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;
}

如下图,调试中生成了最终的代理类


image.png

至此,整个的代理类的实现过程就全部完成了。

总结下整个AOP注解操作的过程

1、先利用xml配置,添加AnnotationAwareAspectJAutoProxyCreator类到IOC容器中
2、在实例化各种beanpostprocessor的时候,扫描IOC所有的bean,如果配置了includePattern属性,还需要对IOC容器的所有bean进行正则匹配,通过的才会进行接下来的操作
3、所有合适的bean遍历找到注解为@Aspect的类,轮询bean的方法,如果包含了Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的注解方法,也需要收集起来,最后形成kv对,添加到AnnotationAwareAspectJAutoProxyCreator的cache容器中
4、实例化被代理的类之前需要实例化本身
5、从AnnotationAwareAspectJAutoProxyCreator存储的所有advisor匹配出符合规则的advisor

具体可看AopUtils抽象类的findAdvisorsThatCanApply 方法

6、最后生成一个ProxyFactory,添加上述得到的各种数据,生成代理类

再来回答文章前提到的几个问题

无需再强调,如果还是无法理解,可以仔细阅读spring xml的bean提取 源码学习,带来的作用就是新增了一个管理Aspect的类,所有的advisor都是存放在这个类中

beanpostprocessor实例化的时候,特指org.springframework.context.event.internalEventListenerProcessor类的实例化时,会去扫描所有的bean,检查是否存在@Aspect注解,如果有该注解,则添加到AnnotationAwareAspectJAutoProxyCreator中

切入点是按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class自定义的排序规则sort的操作的

相互独立的,只有在bean具体生成的时候从AnnotationAwareAspectJAutoProxyCreator中获取到合适的切面以及切点信息,最后生成代理类。

上一篇下一篇

猜你喜欢

热点阅读