配置Spring AOP aspectj-autoproxy标签源码解析

配置AOP标签

在配置文件中配置了以下标签,即可开启AOP:

<aop:aspectj-autoproxy />

此标签有以下两个属性:

<aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="false"/>

开启AOP之后:会使用AspectJAutoProxyBeanDefinitionParser()解析器进行解析

解析器初始化的操作:

public class AopNamespaceHandler extends NamespaceHandlerSupport {
    public 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());
    }
}

这些解析器都是对BeanDefinitionParser接口的实现,所以入口都是parse()方法。

BeanDefinitionParser接口源码:

public interface BeanDefinitionParser {
    BeanDefinition parse(Element var1, ParserContext var2);
}

一旦遇到aspectj-autoproxy就会使用AspectJAutoProxyBeanDefinitionParser解析器进行解析:

AspectJAutoProxyBeanDefinitionParser解析器源码:

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
    AspectJAutoProxyBeanDefinitionParser() {
    }

    // 解析器的入口
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        // 注册AnnotationAutoProxyCreator
        AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
        // 对注解的子类处理,扩展操作
        this.extendBeanDefinition(element, parserContext);
        return null;
    }

//...省略其他源码
}

主要是registerAspectJAnnotationAutoProxyCreatorIfNecessary这个方法,以下是这个方法的源码:

// 注册AnnotationAutoProxyCreator 
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
    // 注册或者升级
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    // 对于proxy-target-class和expose-proxy属性的处理
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    // 注册组件并通知,便于监听器做进一步处理
    registerComponentIfNecessary(beanDefinition, parserContext);
}

下面分别是registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法的源码和useClassProxyingIfNecessary()方法的源码

1、注册AnnotationAwareAspectJAutoProxyCreator自动代理创建器或者升级自动代理创建器为AnnotationAwareAspectJAutoProxyCreator自动代理创建器

对于AOP的实现基本上都是靠AnnotationAwareAspectJAutoProxyCreator去完成的

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, Object source) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    // 如果已经存在自动代理创建器
    if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
        BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
        //如果自动代理创建器与现在的不一致,需要根据优先级来判断到底需要使用哪个
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            // 获取当前的自动代理创建器的优先级
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            // 获取AnnotationAwareAspectJAutoProxyCreator自动代理创建器的优先级
            int requiredPriority = findPriorityForClass(cls);
            // 如果优先级小于AnnotationAwareAspectJAutoProxyCreator自动代理创建器的优先级,则将当前的升级为AnnotationAwareAspectJAutoProxyCreator自动代理创建器,大于则不需要升级
            if (currentPriority < requiredPriority) {
            // 改变bean最重要的就是改变bean所对应的className属性 
            apcDefinition.setBeanClassName(cls.getName());
            }
        }
        // 当前的的自动代理创建器就是AnnotationAwareAspectJAutoProxyCreator自动代理创建器,不在创建
        return null;
        } else {
            // 不存在自动代理创建器,创建AnnotationAwareAspectJAutoProxyCreator自动代理创建器
            RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
            beanDefinition.setSource(source);
            beanDefinition.getPropertyValues().add("order", -2147483648);
            beanDefinition.setRole(2);
            registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
            return beanDefinition;
        }
}

2、对于proxy-target-class和expose-proxy属性的处理

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
    if (sourceElement != null) {
        boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute("proxy-target-class")).booleanValue();
        // 处理proxy-target-class属性
        if (proxyTargetClass) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }

        boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute("expose-proxy")).booleanValue();
        // 处理expose-proxy属性
        if (exposeProxy) {
           AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
        }
    }
}

proxy-target-class属性:用来设置JDK动态代理和CGLIB动态代理之间的切换

<aop:aspectj-autoproxy proxy-target-class="false"/>

默认为false表示使用JDK动态代理。如果实现了至少一个接口,Spring会优先选择使用JDK动态代理,若果没有实现任何接口,则spring会选择CGLIB动态代理,强制使用CGLIB动态代理,使用以下配置:

<aop:aspectj-autoproxy proxy-target-class="true"/>

epose-proxy属性:暴露当前的代理对象

springAOP 只会拦截public方法,不会拦截provided和private方法,并且不会拦截public方法内部调用的其他方法,也就是说只会拦截代理对象的方法,即增强的是代理对象,而不是原对象。

<aop:aspectj-autoproxy expose-proxy="true"/>

通过上面的设置就可以暴露出代理对象,拦截器会获取代理对象,并且将代理对象转换成原对象。从而对内部调用的方法进行增强。


声明:本文是自己学习《Spring 源码深度解析》一书的笔记,为了给自己加深印象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值