Spring与AOP

AOP是Spring的两大特性之一,本文再来回顾一下AOP的原理

示例

首先定义一个切点:

1
2
3
4
5
6
7
8
9
10
11
public interface Performance {
void perform();
}

@Component
public class PerformanceImpl implements Performance {
@Override
public void perform() {
System.out.println("performing...");
}
}

然后定义一个切面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Aspect
@Component
public class Audience {
@Pointcut("execution(* love.test.Performance.perform(..))")
public void performance() {}

@Before("performance()")
public void silenceCellPhone() {
System.out.println("Silencing cell phones");
}

@After("performance()")
public void after() {
System.out.println("after");
}

@AfterReturning("performance()")
public void applause() {
System.out.println("CLAP CLAP CLAP");
}
}

最后定义一个配置类和一个启动类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {
}

public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConcertConfig.class);
Performance performance = context.getBean(Performance.class);
performance.perform();
context.close();
}
}

最后的输出为

1
2
3
4
Silencing cell phones
performing...
after
CLAP CLAP CLAP

解析配置类

执行到invokeBeanFactoryPostProcessors方法,获取实现了BeanDefinitionRegistryPostProcessor接口的类:ConfigurationClassPostProcessor

ConfigurationClassPostProcessorprocessConfigBeanDefinitions方法中处理配置类。

首先调动ConfigurationClassParser.parse方法解析配置类。核心方法是processImports(configClass, sourceClass, getImports(sourceClass), true)

首先调用getImports(sourceClass)方法获取配置类中的Import注释。这里只有一个:org.springframework.context.annotation.AspectJAutoProxyRegistrar。然后在getImports方法中加入到ConfigurationClassimportBeanDefinitionRegistrars中:

1
2
3
4
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

加载beanDefinition

调用this.reader.loadBeanDefinitions(configClass)根据配置类加载额外的beanDefinition。

在之前的配置类解析中,因为@EnableAspectJAutoProxy注释的存在,ConfigurationClassimportBeanDefinitionRegistrars中有一个key为AspectJAutoProxyRegistrar,value为StandardAnnotationMetadata的map。

因此在loadBeanDefinitionsForConfigurationClass方法中调用loadBeanDefinitionsFromRegistrars,进入AspectJAutoProxyRegistrar.registerBeanDefinitions方法,该方法会注册一个名为”org.springframework.aop.config.internalAutoProxyCreator”的beanDefintion,类为org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator

注册BeanPostProcessor

经过前面加载了beanDefinition,在registerBeanPostProcessors方法中将AnnotationAwareAspectJAutoProxyCreator注册为BeanPostProcessor

bean实例化与初始化

bean创建工作在DefaultListableBeanFactory.doCreateBean中完成:

  1. 调用AbstractAutowireCapableBeanFactory.createBeanInstance创建bean实例。
  2. 调用AbstractAutowireCapableBeanFactory.populateBean填充bean实例。
  3. 调用AbstractAutowireCapableBeanFactory.initializeBean初始化bean实例

在调用initializeBean来初始化bean实例的代码中,applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)方法遍历所有的BeanPostProcessor,调用其postProcessAfterInitialization方法。

重点关注AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization,它调用AbstractAutoProxyCreator.wrapIfNecessary如果需要代理则返回经过包装的代理类:

  1. 调用AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean寻找指定bean的Advisor。
  2. 如果返回的advisor不为null,说明需要创建代理。调用createProxy方法对给定的bean创建一个AOP代理,其调用ProxyFactory.getProxy方法,该方法只有一行代码:
1
2
3
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}

先调用createAopProxy创建AopProxy,再调用getProxy获取代理对象。

回到AbstractAutowireCapableBeanFactory.initializeBean方法,wrappedBean再经过applyBeanPostProcessorsAfterInitialization处理,调用AbstractAutoProxyCreator.postProcessAfterInitialization,wrappedBean变成了一个代理类。

AOP代理对象的调用

当调用aop代理类的方法时,调用的实际上是JdkDynamicAopProxy.invoke:

  1. 首先调用List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)获取这个方法的拦截链
  2. 调用MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain)创建MethodInvocation,将我们之前的代理、目标对象、拦截的method名称、拦截方法的参数、拦截器链全部整合到了ReflectiveMethodInvocation这个类中
  3. 然后调用ReflectiveMethodInvocation.proceed执行一串拦截链