Spring AOP源码解析
AOP核心概念
官网地址:https://docs.spring.io/spring/docs/5.2.8.RELEASE/spring-framework-reference/core.html#aop-introduction-defn
AOP基本概念
Spring包含的五种通知
AOP代理方式
Spring AOP有两种代理方式:JDK 动态代理和CGLIB动态代理;默认使用JDK动态代理
Spring中AOP用法
pom配置
在pom.xml中依赖两个jar包,如下:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
目标类
public class BeanQ {
public void do1(String task, int time) {
System.out.println("-------------do1 do " + task + " time:" + time);
}
public String service1(String name) {
System.out.println("-------------servce1 do " + name);
return name;
}
public String service2(String name) {
System.out.println("-------------servce2 do " + name);
if (!"s1".equals(name)) {
throw new IllegalArgumentException("参数 name != s1, name=" + name);
}
return name + " hello!";
}
}
Advisor方式
基于Advice接口的类实现
-
掌握用法:
编程提供Advice,实现对应的Advice接口
配置Advisor (advice + pointcut)
-
Xml 配置方式
注意点:aop:config 的属性了解
-
掌握spring Aop 的API
Advice:接口实现
Pointcut:字符串表达式
Advisor:xml标签配置
application.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="BeanQ" class="edu.dongnao.courseware.spring.aop.BeanQ" />
<!--将advice做为bean放入容器-->
<bean id="myBeforeAdvice" class="edu.dongnao.courseware.spring.aop.MyBeforeAdvice" />
<bean id="yyArroundAdvice" class="edu.dongnao.courseware.spring.aop.MyArroundAdvice" />
<!--第一种方式:advisor 配置切点和通知,aop下以do开头的方法-->
<!--
expose-proxy="false" 是否暴露当前代理对象为ThreadLocal模式
proxy-target-class="false" 是否使用代理类的形式
-->
<aop:config>
<aop:pointcut id="doMethods" expression="execution(* edu.dongnao.courseware.spring.aop.*.do*(..))" />
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="doMethods" />
<aop:advisor advice-ref="yyArroundAdvice"
pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))"/>
</aop:config >
<!-- 配置了包含advice方法的Bean -->
<bean id="aspectAdviceBean" class="edu.dongnao.courseware.spring.aop.AspectAdviceBean" />
<!--第二种方式:aspect-->
<!--proxy-target-class表示使用CGLIB方式处理代理类-->
<!--aop下以service开头的方法-->
<aop:config>
<aop:pointcut id="services" expression="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))" />
<aop:aspect id="a1" ref="aspectAdviceBean" order="1">
<aop:before method="before1" pointcut-ref="doMethods" />
<aop:before method="before2" pointcut-ref="doMethods"/>
<!--
and args(tk,..),还需要匹配参数,第一个参数类型必须与Advice中tk一致
arg-name
-->
<aop:before method="before3" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,..)"/>
<aop:before method="before4" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,ti)"/>
<aop:around method="arround1" pointcut-ref="services"/>
<aop:around method="arround2" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..)) and args(name)"/>
<aop:after-returning method="afterReturning" pointcut-ref="services" returning="retValue"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="services" throwing="e"/>
<aop:after method="after" pointcut-ref="services"/>
</aop:aspect>
</aop:config>
<bean id="aspectAdviceBeanUseAnnotation" class="edu.dongnao.courseware.spring.aop.AspectAdviceBeanUseAnnotation" />
</beans>
通知接口实现
/**
前置通知
*/
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("------ MyBeforeAdvice before 增强 " + target + " " + method);
}
}
/**
环绕通知
*/
public class MyArroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("--------- 环绕 -前增强");
Object ret = invocation.proceed();
System.out.println("--------- 环绕 -后增强");
return ret;
}
}
Aspect方式
Aspect的advice是基于方法的。
掌握它的用法:
-
定义包含Advice方法的Bean 类
-
配置Bean 定义
-
配置Aspect (引用包含advice方法的bean),在里面配置各种Advice(method + pointcut)
Aspect的XML方式
Xml 配置方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="BeanQ" class="edu.dongnao.courseware.spring.aop.BeanQ" />
<!--将advice做为bean放入容器-->
<bean id="myBeforeAdvice" class="edu.dongnao.courseware.spring.aop.MyBeforeAdvice" />
<bean id="yyArroundAdvice" class="edu.dongnao.courseware.spring.aop.MyArroundAdvice" />
<!--第一种方式:advisor 配置切点和通知,aop下以do开头的方法-->
<!--
expose-proxy="false" 是否暴露当前代理对象为ThreadLocal模式
proxy-target-class="false" 是否使用代理类的形式
-->
<aop:config>
<aop:pointcut id="doMethods" expression="execution(* edu.dongnao.courseware.spring.aop.*.do*(..))" />
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="doMethods" />
<aop:advisor advice-ref="yyArroundAdvice"
pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))"/>
</aop:config >
<!-- 配置了包含advice方法的Bean -->
<bean id="aspectAdviceBean" class="edu.dongnao.courseware.spring.aop.AspectAdviceBean" />
<!--第二种方式:aspect-->
<!--proxy-target-class表示使用CGLIB方式处理代理类-->
<!--aop下以service开头的方法-->
<aop:config>
<aop:pointcut id="services" expression="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))" />
<aop:aspect id="a1" ref="aspectAdviceBean" order="1">
<aop:before method="before1" pointcut-ref="doMethods" />
<aop:before method="before2" pointcut-ref="doMethods"/>
<!--
and args(tk,..),还需要匹配参数,第一个参数类型必须与Advice中tk一致
arg-name
-->
<aop:before method="before3" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,..)"/>
<aop:before method="before4" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,ti)"/>
<aop:around method="arround1" pointcut-ref="services"/>
<aop:around method="arround2" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..)) and args(name)"/>
<aop:after-returning method="afterReturning" pointcut-ref="services" returning="retValue"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="services" throwing="e"/>
<aop:after method="after" pointcut-ref="services"/>
</aop:aspect>
</aop:config>
<bean id="aspectAdviceBeanUseAnnotation" class="edu.dongnao.courseware.spring.aop.AspectAdviceBeanUseAnnotation" />
</beans>
通知类
public class AspectAdviceBean {
public void before1() {
System.out.println("----------- AspectAdviceBean before1 增强 ");
}
public void before2(JoinPoint jp) {
System.out.println("----------- AspectAdviceBean before2 增强 for " + jp);
}
/*
* 也可以不需要joinpoint
*/
public void before3(String tk) {
System.out.println("----------- AspectAdviceBean before3 增强 参数tk= " + tk);
}
public void before4(String tk, int ti) {
System.out.println("----------- AspectAdviceBean before4 增强 参数tk= " + tk + " ti=" + ti);
}
/*
* 如果需要joinpoint,就作为第一个参数传入使用。
*/
public Object arround1(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("----------- AspectAdviceBean arround1 环绕-前增强 for " + pjp);
Object ret = pjp.proceed();
System.out.println("----------- AspectAdviceBean arround1 环绕-后增强 for " + pjp);
return ret;
}
public Object arround2(ProceedingJoinPoint pjp, String name) throws Throwable {
System.out.println("--------- AspectAdviceBean arround2 参数 name=" + name);
System.out.println("----------- AspectAdviceBean arround2 环绕-前增强 for " + pjp);
Object ret = pjp.proceed();
System.out.println("----------- AspectAdviceBean arround2 环绕-后增强 for " + pjp);
return ret;
}
public void afterReturning(Object retValue) {
System.out.println("----------- AspectAdviceBean afterReturning 增强 , 返回值为: " + retValue);
}
/*
* 因为需要对异常进行处理,所以需要Exception参数
*/
public void afterThrowing(JoinPoint jp, Exception e) {
System.out.println("----------- AspectAdviceBean afterThrowing 增强 for " + jp);
System.out.println("----------- AspectAdviceBean afterThrowing 增强 异常 :" + e);
}
public void after(JoinPoint jp) {
System.out.println("----------- AspectAdviceBean after 增强 for " + jp);
}
}
Aspect的注解方式
配置@Aspect切面
@Aspect
public class AspectAdviceBeanUseAnnotation {
// 定义一个全局的Pointcut
@Pointcut("execution(* edu.dongnao.courseware.spring.aop.*.do*(..))")
public void doMethods() {
}
@Pointcut("execution(* edu.dongnao.courseware.spring.aop.*.service*(..))")
public void services() {
}
// 定义一个Before Advice
@Before("doMethods() and args(tk,..)")
public void before3(String tk) {
System.out.println("----------- AspectAdviceBeanUseAnnotation before3 增强 参数tk= " + tk);
}
@Around("services() and args(name,..)")
public Object around2(ProceedingJoinPoint pjp, String name) throws Throwable {
System.out.println("--------- AspectAdviceBeanUseAnnotation arround2 参数 name=" + name);
System.out.println("----------- AspectAdviceBeanUseAnnotation arround2 环绕-前增强 for " + pjp);
Object ret = pjp.proceed();
System.out.println("----------- AspectAdviceBeanUseAnnotation arround2 环绕-后增强 for " + pjp);
return ret;
}
@AfterReturning(pointcut = "services()", returning = "retValue")
public void afterReturning(Object retValue) {
System.out.println("----------- AspectAdviceBeanUseAnnotation afterReturning 增强 , 返回值为: " + retValue);
}
@AfterThrowing(pointcut = "services()", throwing = "e")
public void afterThrowing(JoinPoint jp, Exception e) {
System.out.println("----------- AspectAdviceBeanUseAnnotation afterThrowing 增强 for " + jp);
System.out.println("----------- AspectAdviceBeanUseAnnotation afterThrowing 增强 异常 :" + e);
}
@After("doMethods()")
public void after(JoinPoint jp) {
System.out.println("----------- AspectAdviceBeanUseAnnotation after 增强 for " + jp);
}
/*
* BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor
* InstantiationAwareBeanPostProcessor Bean实例创建前后 BeanPostProcessor
*/
}
开启方式
Xml 开启@Aspectj注解
Xml中aop:aspectj-autoproxy</aop:aspectj-autoproxy> 注意了解它的属性、及子元素:指定AOP的过滤
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="BeanQ" class="edu.dongnao.courseware.spring.aop.BeanQ" />
<bean id="aspectAdviceBeanUseAnnotation" class="edu.dongnao.courseware.spring.aop.AspectAdviceBeanUseAnnotation" />
<aop:aspectj-autoproxy>
<!--只有符合名字表达式的bean才会进行代理创建-->
<!--<aop:include name="thisBean" />-->
</aop:aspectj-autoproxy>
</beans>
注解开启@Aspectj注解
@Configuration
@EnableAspectJAutoProxy //注解开启
public class AppConfig {
}
Advice接口体系
PointCut接口体系
Advisor接口体系
JointPoint接口体系
JointPoint结构
接口体系
Spring AOP源码分析
Spring AOP工作流程

配置的解析过程
XML解析入口
<aop:config>
<aop:pointcut id="doMethods" expression="execution(* edu.dongnao.courseware.spring.aop.*.do*(..))" />
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="doMethods" />
<aop:advisor advice-ref="yyArroundAdvice"
pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))"/>
</aop:config >
从aop:config标签的解析开始,看解析这个标签都做了什么。
查找aop的jar包的meta-info目录,找到对应的Handler,AopNamespaceHandler。
/**
* {@code NamespaceHandler} for the {@code aop} namespace.
*
* <p>Provides a {@link org.springframework.beans.factory.xml.BeanDefinitionParser} for the
* {@code <aop:config>} tag. A {@code config} tag can include nested
* {@code pointcut}, {@code advisor} and {@code aspect} tags.
*
* <p>The {@code pointcut} tag allows for creation of named
* {@link AspectJExpressionPointcut} beans using a simple syntax:
* <pre class="code">
* <aop:pointcut id="getNameCalls" expression="execution(* *..ITestBean.getName(..))"/>
* </pre>
*
* <p>Using the {@code advisor} tag you can configure an {@link org.springframework.aop.Advisor}
* and have it applied to all relevant beans in you {@link org.springframework.beans.factory.BeanFactory}
* automatically. The {@code advisor} tag supports both in-line and referenced
* {@link org.springframework.aop.Pointcut Pointcuts}:
*
* <pre class="code">
* <aop:advisor id="getAgeAdvisor"
* pointcut="execution(* *..ITestBean.getAge(..))"
* advice-ref="getAgeCounter"/>
*
* <aop:advisor id="getNameAdvisor"
* pointcut-ref="getNameCalls"
* advice-ref="getNameCounter"/></pre>
*
* @author Rob Harrop
* @author Adrian Colyer
* @author Juergen Hoeller
* @since 2.0
*/
public class AopNamespaceHandler extends NamespaceHandlerSupport {
/**
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*/
@Override
public void init() {
// In 2.0 XSD as well as in 2.5+ XSDs
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace in 2.5+
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
Config XML的解析
ConfigBeanDefinitionParser#parse方法
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
// 配置自动代理构造器
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
// pointcout切点元素解析处理
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
// advisor通知者元素解析处理
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
// aspect方面元素解析
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
configureAutoProxyCreator()
/**
* Configures the auto proxy creator needed to support the {@link BeanDefinition BeanDefinitions}
* created by the '{@code <aop:config/>}' tag. Will force class proxying if the
* '{@code proxy-target-class}' attribute is set to '{@code true}'.
* @see AopNamespaceUtils
*/
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
registerAspectJAutoProxyCreatorIfNecessary()
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary
注册AutoProxyCreator
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
// 工厂中有配置的自动代理构造器,则与前面传递的cls构造器进行优先级对比
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
// 找cls的优先等级,这里是指AspectJAwareAdvisorAutoProxyCreator.class
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {// 优先等级大的则会被使用
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 如果不包含AUTO_PROXY_CREATOR_BEAN_NAME的bean定义,则构建注册一个
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
org.springframework.aop.config.AopConfigUtils#APC_PRIORITY_LIST
里面装了对应的自动代理创建者的优先等级信息,其实就是索引值
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
当在xml中配置了aop:aspectj-autoproxy,则会选择AnnotationAwareAspectJAutoProxyCreator。
AspectJAwareAdvisorAutoProxyCreator的继承体系
AutoProxyCreator 是一个BeanPostProcessor、还是BeanFactoryAware,还是ProxyConfig。通过BeanPostProcessor机制,它将负责创建代理对象。
AbstractAutoProxyCreator实现
就是我们前面看到的三个不同优先等级的AutoProxyCreator。
AopConfig
AOP配置类ProxyConfig
从aop:config 元素读取配置属性proxy_target_class、expose_proxy,存放在ProxyConfig 类中。
AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary
// AspectJ自动代理构建器
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
// 属性的处理
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying
public 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);
}
}
其他元素解析
ConfigBeanDefinitionParser#parse****的其他方法
pointcut、advisor、aspect解析成对应的bean定义
pointcut对应AspectJExpressionPointcut类型bean
advisor对应DefaultBeanFactoryPointcutAdvisor类型bean
aspect对应下的子元素解析,Advisor类型的bean
注解方式配置的解析
在xml中配置aop:aspectj-autoproxy/或者通过@EnableAspectJAutoProxy注解类开启。这里我们仍然通过xml中的配置来寻找入口,不难就能在AopNameSpaceHandler.init方法找到aspectj-autoproxy的解析,对应着AspectJAutoProxyBeanDefinitionParser类解析器。
AspectJAutoProxyBeanDefinitionParser
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 注册方面注解自动代理构造器
// 做的事情跟前面的config中构建AutoProxyCreator类似
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 处理子标签include
extendBeanDefinition(element, parserContext);
return null;
}
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary的方法
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
//注册一个 AnnotationAwareAspectJAutoProxyCreator 的BeanDefinition
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator是AspectJAwareAdvisorAutoProxyCreator的子类,具有AspectJAwareAdvisorAutoProxyCreator的所有功能,并且还提供对注解的支持,往容器中注入它,用来处理注解的AOP。
注解方式的切面加载
xml方式的切面信息加载在ConfigBeanDefinitionParser.parse方法中进行了解析加载,通过源码分析,发现注解方式的并没有进行解析加载,那么提出几个疑问:
Advisor、Pointcut、Aspect信息在哪里进行了加载呢?
回到AnnotationAwareAspectJAutoProxyCreator类,查找可疑的方法,带有advisor关键字的方法。
AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 通过父类的同名方法,加载通过xml配置方式的advisor信息
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
// 加载beanFacotory中的advisor信息,
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
通过父类的同名方法,加载通过xml配置方式的advisor信息
super.findCandidateAdvisors()
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
/**
* Find all eligible Advisor beans in the current bean factory,
* ignoring FactoryBeans and excluding beans that are currently in creation.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] 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!
//查找Advisor的bean
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("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;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("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;
}
在看aspectJAdvisorsBuilder.buildAspectJAdvisors()获取的advisor,看下aspectJAdvisorsBuilder初始化
AnnotationAwareAspectJAutoProxyCreator#initBeanFactory方法,这个方法是在其父类AbstractAdvisorAutoProxyCreator的setBeanFactory方法中调用,这个方法是也就是初始化之前
方法实现:
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
}
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}
AnnotationAwareAspectJAutoProxyCreator#initBeanFactory方法
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
// 构建切面反射的advisor工厂,用来创建ApectJ配置类型的advisors
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
// 传递了beanFactory、aspectJAdvisorFactory,实例化aspectJAdvisorsBuilder
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
BeanFactoryAspectJAdvisorsBuilderAdapter.buildAspectJAdvisors方法
重点观察advisorFactory实例被调用的地方
/**
* Look for AspectJ-annotated aspect beans in the current bean factory,
* and return to a list of Spring AOP Advisors representing them.
* <p>Creates a Spring Advisor for each AspectJ advice method.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
/**
* 方法的逻辑:<br>
* 1、看有没有缓存下带有@Ascpect注解的Bean的名字:aspectBeanNames。<br>
* 2、没有这个缓存的名字,表示这是第一次来创建AspectJAdvisors,则获取BeanFactory中所有的beanNames;<br>
* 遍历beanNames,获取每个beanName对应的Class,看它上面有没有@Aspect注解,有则提前它里面的注解advice,创建Advisor;
* <br>
* 并缓存下创建的Advisor,缓存记录BeanName,返回Advisor <br>
* 3、有这个缓存表示已经创建过了,则直接从缓存中获取缓存的Advisor,返回。
*/
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
// 刚开始为null,查找所有的切面bean的名字,并且实例化返回
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
//获取所有的bean定义的名字
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
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.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 判断是否为一个切面配置,@Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 单例模式的advisor
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//重点: 解析并构建获得advisor列表
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// xml配置aspect bean范围,或者@Aspect中配置bean范围
// 如果bean本身是单例的,则缓存创建的advisors,advisor就是单例方式
// 如果bean不是单例的,则缓存advisor的factory,advisor也就不是单例的
if (this.beanFactory.isSingleton(beanName)) {
// 单例advisor缓存起来
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// 非单例,缓存工厂
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// 非单例模式advisor处理
// 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));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 再次执行,从缓存获取
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
// 单例advisor从缓存获取,非单例由advisor工厂再次构建获得
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;
}
ReflectiveAspectJAdvisorFactory.getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 加载构建advisor
for (Method method : getAdvisorMethods(aspectClass)) {
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
主要实现在ReflectiveAspectJAdvisorFactory#getAdvisor方法
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获得切点
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 实例化一个advisor
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
再看看getPointcut、getAdvice方法。
什么时候加载?
我们找到的这个方法对不对?在什么时候加载?我们在ReflectiveAspectJAdvisorFactory.getAdvisors 方法上打上断点,进行一波调试,查看调用堆栈信息。
// 断点地方
getAdvisors(MetadataAwareAspectInstanceFactory):120,
ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
buildAspectJAdvisors():110, BeanFactoryAspectJAdvisorsBuilder
(org.springframework.aop.aspectj.annotation)
findCandidateAdvisors():95, AnnotationAwareAspectJAutoProxyCreator
(org.springframework.aop.aspectj.annotation)
shouldSkip(Class, String):101, AspectJAwareAdvisorAutoProxyCreator
(org.springframework.aop.aspectj.autoproxy)
postProcessBeforeInstantiation(Class, String):251, AbstractAutoProxyCreator
(org.springframework.aop.framework.autoproxy)
// 在bean对象实例化之前的BenPostProcessor,即InstantiationAwareBeanPostProcessor
applyBeanPostProcessorsBeforeInstantiation(Class, String):1140,
AbstractAutowireCapableBeanFactory
(org.springframework.beans.factory.support)
resolveBeforeInstantiation(String, RootBeanDefinition):1113,
AbstractAutowireCapableBeanFactory
(org.springframework.beans.factory.support)
createBean(String, RootBeanDefinition, Object[]):505,
AbstractAutowireCapableBeanFactory
(org.springframework.beans.factory.support)
lambda$doGetBean$0(String, RootBeanDefinition, Object[]):324,
AbstractBeanFactory (org.springframework.beans.factory.support)
getObject():-1, 943870983
(org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$45)
getSingleton(String, ObjectFactory):226, DefaultSingletonBeanRegistry
(org.springframework.beans.factory.support)
doGetBean(String, Class, Object[], boolean):322, AbstractBeanFactory
(org.springframework.beans.factory.support)
getBean(String):202, AbstractBeanFactory
(org.springframework.beans.factory.support)
preInstantiateSingletons():897, DefaultListableBeanFactory
(org.springframework.beans.factory.support)
finishBeanFactoryInitialization(ConfigurableListableBeanFactory):879,
AbstractApplicationContext (org.springframework.context.support)
refresh():551, AbstractApplicationContext
(org.springframework.context.support)
<init>(String[]):71, GenericXmlApplicationContext
(org.springframework.context.support)
main(String[]):8, AopMainUseAspectAnnotation
(edu.dongnao.courseware.spring.aop)
可以得知,在IOC容器初始化刷新里提前创建单例bean的流程中,单例bean实例化之前进行加载解析。
ans.factory.support)
lambda$doGetBean
0
(
S
t
r
i
n
g
,
R
o
o
t
B
e
a
n
D
e
f
i
n
i
t
i
o
n
,
O
b
j
e
c
t
[
]
)
:
324
,
A
b
s
t
r
a
c
t
B
e
a
n
F
a
c
t
o
r
y
(
o
r
g
.
s
p
r
i
n
g
f
r
a
m
e
w
o
r
k
.
b
e
a
n
s
.
f
a
c
t
o
r
y
.
s
u
p
p
o
r
t
)
g
e
t
O
b
j
e
c
t
(
)
:
−
1
,
943870983
(
o
r
g
.
s
p
r
i
n
g
f
r
a
m
e
w
o
r
k
.
b
e
a
n
s
.
f
a
c
t
o
r
y
.
s
u
p
p
o
r
t
.
A
b
s
t
r
a
c
t
B
e
a
n
F
a
c
t
o
r
y
0(String, RootBeanDefinition, Object[]):324, AbstractBeanFactory (org.springframework.beans.factory.support) getObject():-1, 943870983 (org.springframework.beans.factory.support.AbstractBeanFactory
0(String,RootBeanDefinition,Object[]):324,AbstractBeanFactory(org.springframework.beans.factory.support)getObject():−1,943870983(org.springframework.beans.factory.support.AbstractBeanFactory$Lambda$45)
getSingleton(String, ObjectFactory):226, DefaultSingletonBeanRegistry
(org.springframework.beans.factory.support)
doGetBean(String, Class, Object[], boolean):322, AbstractBeanFactory
(org.springframework.beans.factory.support)
getBean(String):202, AbstractBeanFactory
(org.springframework.beans.factory.support)
preInstantiateSingletons():897, DefaultListableBeanFactory
(org.springframework.beans.factory.support)
finishBeanFactoryInitialization(ConfigurableListableBeanFactory):879,
AbstractApplicationContext (org.springframework.context.support)
refresh():551, AbstractApplicationContext
(org.springframework.context.support)
(String[]):71, GenericXmlApplicationContext
(org.springframework.context.support)
main(String[]):8, AopMainUseAspectAnnotation
(edu.dongnao.courseware.spring.aop)
可以得知,在IOC容器初始化刷新里提前创建单例bean的流程中,单例bean实例化之前进行加载解析。