一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
Spring源码系列(四):AOP流程源码分析
AOP执行过程流程图
![AOP代理流程分析.png]
测试类
-
spring-aop.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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <!--目标对象--> <bean id="userService" class="com.ming.aop.UserServiceImpl"/> <!--切面对象--> <bean id="myAspect" class="com.ming.aop.MyAspect"/> <!--配置织入:告诉spring框架,哪些方法(切点)需要进行增强(前置、后置...--> <aop:config> <!--抽取切点表达式--> <aop:pointcut id="myPointcut" expression="execution(* com.ming.aop.*.*(..))"/> <!--声明切面--> <aop:aspect ref="myAspect"> <!--抽取切点表达式--> <!--<aop:pointcut id="myPointcut" expression="execution(* com.ming.aop.*.*(..))"/>--> <!--切面:切点+通知--> <aop:before method="before" pointcut="execution( * com.ming.aop.*.*(..))"/> <aop:after-returning method="afterReturning" pointcut="execution( * com.ming.aop.*.*(..))"/> <aop:around method="around" pointcut="execution(* com.ming.aop.*.*(..))"/> <aop:after-throwing method="afterThrowing" pointcut="execution(* com.ming.aop.*.*(..))"/> <aop:after method="after" pointcut="execution(* com.ming.aop.*.*(..))"/> <aop:around method="around" pointcut-ref="myPointcut"/> <aop:after method="after" pointcut-ref="myPointcut"/> </aop:aspect> </aop:config> </beans> -
MyAspect.java 切面对象
public class MyAspect { public void before() { System.out.println("前置增强......."); } public void afterReturning() { System.out.println("后置增强......."); } // ProceedJoinPoint:正在执行的连接点 == 切点 public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕前增强......."); Object proceed = pjp.proceed(); // 切点方法 System.out.println("环绕后增强......."); return proceed; } public void afterThrowing() { System.out.println("异常抛出增强......."); } public void after() { System.out.println("最终增强......."); } } -
UserServiceImpl 被代理类,实现了UserService接口
public class UserServiceImpl implements UserService{ @Override public void saveUser() { System.out.println("save user....."); } }
产生AOP代理流程分析
我们知道在spring配置文件中,除了import、alias、bean、beans 标签外别都是属于自定义标签,spring会在执行refresh中的第二个方法obtainFreshBeanFactory() 时被解析到spring工厂中去,例如当我们在配置文件中配置了<context:component-scan />标签,spring就会找到处理这个标签的BeanDefinitionParser来进行解析。
如果不明白这一部分可以看我的另外一篇文章:juejin.cn/post/708130…
AOP的执行流程也是如此,我们只不过是在配置文件中配置了<aop:xxx/>,所以解析这个标签的时候也会找到一个BeanDefinitionParser也解析,这个类就是ConfigBeanDefinitionParser。我们找到这个类的parse方法。
configureAutoProxyCreator会获取产生代理对象的创造器,我们指定AOP过程中的目标类后,就会需要代理类,而这个过程就是这个方法来完成的。点进这个方法内部会发现new了一个AspectJAwareAdvisorAutoProxyCreator类。- 这里的for循环主要来处理aop:config下面的aop:xxx标签,aop标签冒号后面的xxx,默认有三种。
- <aop:pointcut />
-
根据parserContext.getDelegate().getLocalName(elt);方法获取到localName,就是aop:xxx/,就是xxx的name,然后通过if判断,这个localName归属于哪个,就执行相应的逻辑。 <aop:pointcut />:切点,这是必要的。我们在配置aop相关的参数的时候,配置pointcut的时机主要有三种。也就是说无论怎么配置,
if (POINTCUT.equals(localName))至少为真执行逻辑一次。<!--第一种,和aop:aspect平级--> <aop:config> <aop:pointcut id="" expression=""/> <aop:aspect/> </aop:config> <!--第二种,在aop:aspect里配置平级--> <aop:config> <aop:aspect> <aop:pointcut id="" expression=""/> </aop:aspect> </aop:config> <!--第三种,在aop:advisor里配置--> <aop:config> <aop:advisor advice-ref="" pointcut="" pointcut-ref=""> </aop:advisor> </aop:config>
-
- aop:asepectj-aspect/
- 我们主要使用的配置方式(AspectJ),配置一个具体的切面(切点+通知)。同时会产生9个对象(见下方代码)
- <aop:scoped-advisor />
-
spring自带的aop方式,会产生两个对象
-
通过解析AOP所有配置的标签的过程(注解配置同理),我们得到了产生代理对象的代理对象创建器,得到配置的多个Advisor(Advice + Pointcut)。下一步我们就要产生具体的代理对象,并执行。Advisor是Ponitcut和Advice的组合对象。一个目标对象可以被多个Advisor进行功能增强
- <aop:pointcut />
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 获取产生代理对象的代理对象创建器
// AspectJAwareAdvisorAutoProxyCreator
configureAutoProxyCreator(parserContext, element);
for (Element elt: childElts) {
// 获取的是aop标签冒号后面的标签名称(aop:pointcut,aop:advisor,aop:aspect)
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
// 产生AspectJExpressionPointcut对象
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
// spring自带的aop功能
// DefaultBeanFactoryPointcutAdvisor
// AspectJExpressionPointcut
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
// AspectJExpressionPointcut 切点表达式
// MethodLocationFactoryBean
// SimpleBeanFactoryAwareAspectInstanceFactory
// AspectJPointcutAdvisor // 具体的Advisor,一个Advisor对应一个Advice
// 五种通知类型
// AspectJAfterReturningAdvice
// AspectJMethodBeforeAdvice
// AspectJAfterAdvice
// AspectJAroundAdvice
// AspectJAfterThrowingAdvice
parseAspect(elt, parserContext);
}
}
}