在springboot中,@EnableAspectJAutoProxy 注解开启AOP , 在这个注解里面,通过@Import 给容器中导入AspectJAutoProxyRegistrar 对象.
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {...}
AspectJAutoProxyRegistrar 实现了ImportBeanDefinitionRegistrar接口,通过这个接口可以向容器中增加Bean的定义。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 这一句往里走,最后创建了一个AnnotationAwareAspectJAutoProxyCreator 对象的Bean定义,加到注册器中,key为org.springframework.aop.config.internalAutoProxyCreator.
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
...
} else {
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;
}
}
在AspectJAutoProxyRegistrar.registerBeanDefinitions() 方法打断点调试,查看调用链路
大致流程是
spring容器启动阶段的 AbstractApplicationContext.refresh()
invokeBeanFactoryPostProcessors(beanFactory) // 调用工厂的后置处理器, 增加即将加入容器中Bean的定义
this**.**reader.loadBeanDefinitions(configClasses); // 加载所有配置类, 有@Configration注解的类
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); // 把配置类中import引入的注册器类加载进来
AspectJAutoProxyRegistrar.registerBeanDefinitions() // 进入到aop的注册bean定义的方法。
通过AnnotationAwareAspectJAutoProxyCreator 类的继承关系,可以看到它实现了BeanPostProcessor. 在spring容器的启动过程中 AbstractApplicationContext.refresh() 有专门负责加载所有实现BeanPostProcessor接口的方法
registerBeanPostProcessors(beanFactory); // 加载所有实现BeanPostProcessor接口的方法
它里面的内容包括如下:
// 获取所有实现了BeanPostProcessor接口的bean的名称
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
...
// 逐个创建Bean
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// BeanFatory.getBean方法获取到的就是已经创建好的Bean了
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
...
// 把创建好的bean加到容器中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
AOP的本质是代理,那么就会有创建Bean的时候,不会使用原本类型指定的对象,而是创建一个增强的对象。那么我们就从创建bean的过程中寻找。我们知道spring 容器启动的过程中,会先加载 BeanPostProcessor 等类型的bean,像我们代码中自己定义的切面等其他业务相关bean,都是之后加载的,从spring容器启动过程的refresh()方法的代码顺序也可以看出来,这一点在这里也不重要,我只是提一下。
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
...
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
既然创建的对象是代理对象,那么直接在AbstractAutowireCapableBeanFactory 类的createBean 方法里面打断点,并且给断电加上Condition, 只在创建我们定义的需要被切的对象的时候断住,比如我写了一个Say这个类,那么我加的条件就是beanName.equals(“say”). 一步步的调试,发现走到applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName) -> wrapIfNecessary(bean, beanName, cacheKey) 方法中的时候,有这么一段代码
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
这个方法是在 AbstractAutoProxyCreator 的 注释也说的很清楚了,如果有通知就创建代理。通过切点表达式和类的关系,就能找到我们定义的通知方法,被封装为Advisor对象。代理创建完成后,可以看到通知方法作为拦截器链添加到了道理对象中。其中的拦截器链已经根据Before, After等注解信息排好了顺序,排序是使用 ReflectiveAspectJAdvisorFactory 类的METHOD_COMPARATOR 方法实现了,里面已经定义好了各个注解的顺序。
至此,需要增强的对象创建完成,调用的时候,进入CglibAopProxy 的 intercept 方法,因为我这里是对类进行的增强,所以spring自动的选则了使用cglib 代理。
先获取所有的增强方法组成的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
把代理对象(Cglib增强后的对象),目标对象(Say),方法,参数,连接器链等信息封装为一个CglibMethodInvocation 对象,并执行该对象的.proceed() 方法。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
调试可以看到链式的调用,逐个拦截器不断的调用 mi.proceed(); 逐渐深入到最后一个拦截器MethodBeforeAdviceInterceptor 的时候,可以看到执行了前置通知的方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
前置通知执行完以后,mo.proceed()方法中满足了执行方法本体的条件,被增强的方法本体执行。
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
执行完后线程栈退回到上一层的拦截器,是AspectJAfterAdvice, 因为是在finally 块中的,所以必然执行。
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
结束后线程退回到AfterReturningAdviceInterceptor 拦截器,到这里为止所有的拦截器中都没有捕获异常,所以如果前面有异常的时候,后置拦截器的内容就不执行了。
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
之后回到AspectJAfterThrowingAdvice 拦截器,这里是在catch 块中,没有异常就不执行。
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
/**
* Author: susq
* Date: 2019-08-04 12:06
*/
public class Say {
public void sayHello() {
log.info("Say -- sayHello : hello !");
}
}
@Aspect
public class SayAspect {
@Pointcut("execution(public * com.su.demo.aop.Say.sayHello(..))")
public void sayPointCut() {}
@After("sayPointCut()")
public void afterSay() {
System.out.println("=====afterSay=====");
}
@AfterThrowing("sayPointCut()")
public void afterThrow() {
System.out.println("=====afterThrow=====");
}
@Before("sayPointCut()")
public void beforeSay() {
System.out.println("=====beforeSay=====");
}
@AfterReturning("sayPointCut()")
public void afterReturn() {
System.out.println("=====afterReturn=====");
}
}
@EnableAspectJAutoProxy
@Configuration
public class SayConfig {
@Bean
public Say say() {
return new Say();
}
@Bean
public SayAspect sayAspect() {
return new SayAspect();
}
}
public class AppTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(SayConfig.class);
Say say = configApplicationContext.getBean(Say.class);
say.sayHello();
}
}