SpringAOP源码之 --- 入口

泄露秘密 提交于 2020-02-24 13:03:38

在查找AOP源码的时候,不知道如何下手,网上找了很多资料,分析源码后,来记录一下AOP的入口:

 

 

BeanDefinition的解析

首先对spring.xml中文件的中的<aop:aspectj-autoproxy/>进行解析,如果发现不是bean标签,则会采用不同的类来解析。解析AOP的是AopNameSpaceHandler,追踪到init中,可以看到如下:

        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); //配置为<aop:aspectj-autoproxy>时,通过这个BeanDefininationParser来处理

进入这个类的parse函数,解析器AspectJAutoProxyBeanDefinitionParser由BeanDefinitionParser接口统一实现:

进入到registerAspectJAnnonationAutoProxyCreatorIfNecessary方法:

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {
//注册或升级AutoProxyCreator,定义的name为org.Springframework.aop.config.internalAutoProxyCreator的beanDefinition
        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));// 对于 proxy-target-class(强制使用cglib) 以及 expose-proxy(是否需要暴露代理接口) 属性的处理
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);// 注册组件并通知,便于监听器作进一步处理    // 其中 beanDefinition 的 className 为 AnnotationAwareAspectJAutoProxyCreator
        registerComponentIfNecessary(beanDefinition, parserContext);
    }

 BeanDefinition的注册

对于AOP的实现上,基本上都是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根据@Point 注解定义的切点来自动代理相匹配的 bean。但是为了配置简便,Spring 使用了自定义配置来帮我们自动注册 AnnotationAwareAspectJAutoProxyCreator。

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   // 如果已经存在自动代理创建器且存在的自动代理创建器与现在的不一致那么需要根据优先级来判断到底需要任何使用
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {     // AUTO_PROXY_CREATOR_BEAN_NAME="org.springframework.aop.config.internalAutoProxyCreator" 
            BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }// 如果已经存在自动代理创建器并且与将要创建的一致,那么无需再此创建
            return null;
        }
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);   // AUTO_PROXY_CREATOR_BEAN_NAME="org.springframework.aop.config.internalAutoProxyCreator" 
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
    }

属性处理

一般而言,Spring AOP 内部使用 JDK 动态代理或者 CGLIB 来为目标对象创建代理。如果被代理的目标对象实现了至少一个接口,则会使用 JDK 动态代理。

所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个 CGLIB 代理。

一般情况下,使用 CGLIB 需要考虑增强(advise)Final 方法不能被复写以及需要指定 CGLIB 包的位置,尽管 CGLIB 效率更高,但还是推荐使用 JDK 动态代理。

而 AOP 配置中的 proxy-target-class 和 expose-proxy 属性在代理生成中起到了至关重要的。prioxy-target-class 主要负责上面两种代理的实现,而 expose-proxy 则负责自我调用切面中的增强。

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
        if (sourceElement != null) {//处理proxy-target-class
            boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
            if (proxyTargetClass) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }//处理expose-proxy
            boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
            if (exposeProxy) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

 

public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }
    }

    static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
        }
    }

下一节将分析AOP的核心,AutoProxyCreator--AnnotationAwareAspectJAutoProxyCreator

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!