Spring源码-AOP(九)-AOP源码分析总结

作者: 阿亮私语 | 来源:发表于2017-09-13 20:24 被阅读250次

前言

至此,AOP相关的源码已经分析结束,接下来我们总结下AOP这块的相关功能,AOP这块的整个分析是从配置文件开始的。这里我们从IOC创建的过程中去分析。
经过之前IOC的分析,我们知道AOP这块也是有bean加载的时候处理的,应该有如下两处。

  • 1、加载bean定义的时候应该有特殊处理
  • 2、getBean的时候有特殊处理

1、加载bean定义的时候

根据之前IOC的源码分析,我们直接定位到DefaultBeanDefinitionDocumentReader这个类的parseBeanDefinitions方法,如果有不熟悉的,请翻阅之前的定义
【DefaultBeanDefinitionDocumentReader】

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

很明显的得知,这里aop不是默认的<bean id = ''>这样的默认Namespace,因此会执行21行的代码
【BeanDefinitionParserDelegate】

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    if (namespaceUri == null) {
        return null;
    }
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

到这里也就能接着AOP入口之前的分析了,接下来主要分析下相应的AOP加载的流程图。
标签加载时序图


下面是AOP标签的处理过程
  • 1、AOP标签的定义解析肯定是从NamespaceHandlerSupport的实现类开始解析的,这个实现类就是AopNamespaceHandler。至于为什么会是从NamespaceHandlerSupport的实现类开始解析的,这个的话我想读者可以去在回去看看Spring自定义标签的解析流程,里面说的比较详细。
  • 2、要启用AOP,我们一般会在Spring里面配置<aop:aspectj-autoproxy/> ,所以在配置文件中在遇到aspectj-autoproxy标签的时候我们会采用AspectJAutoProxyBeanDefinitionParser解析器
  • 3、进入AspectJAutoProxyBeanDefinitionParser解析器后,调用AspectJAutoProxyBeanDefinitionParser已覆盖BeanDefinitionParser的parser方法,然后parser方法把请求转交给了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去处理
  • 4、进入AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法后,先调用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,里面在转发调用给registerOrEscalateApcAsRequired,注册或者升级AnnotationAwareAspectJAutoProxyCreator类。对于AOP的实现,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根据@point注解定义的切点来代理相匹配的bean。
  • 5、AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法处理完成之后,接下来会调用useClassProxyingIfNecessary() 处理proxy-target-class以及expose-proxy属性。如果将proxy-target-class设置为true的话,那么会强制使用CGLIB代理,否则使用jdk动态代理,expose-proxy属性是为了解决有时候目标对象内部的自我调用无法实现切面增强。
  • 6、最后的调用registerComponentIfNecessary 方法,注册组建并且通知便于监听器做进一步处理。

2、创建AOP代理


说明:

  • 1、spring 容器启动,每个bean的实例化之前都会先经过AbstractAutoProxyCreator类的postProcessAfterInitialization()这个方法,然后接下来是调用wrapIfNecessary方法。
  • 2、进入wrapIfNecessary方法后,我们直接看重点实现逻辑的方法getAdvicesAndAdvisorsForBean,这个方法会提取当前bean 的所有增强方法,然后获取到适合的当前bean 的增强方法,然后对增强方法进行排序,最后返回。
  • 3、获取到当前bean的增强方法后,便调用createProxy方法,创建代理。先创建代理工厂proxyFactory,然后获取当前bean 的增强器advisors,把当前获取到的增强器添加到代理工厂proxyFactory,然后设置当前的代理工的代理目标对象为当前bean,最后根据配置创建JDK的动态代理工厂,或者CGLIB的动态代理工厂,然后返回proxyFactory

相关文章

网友评论

    本文标题:Spring源码-AOP(九)-AOP源码分析总结

    本文链接:https://www.haomeiwen.com/subject/revlsxtx.html