AOP是什么
面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的程序设计、剖面导向程序设计),是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。通过在现有代码基础上增加额外的通知(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块进行统一管理与装饰。
怎么在Spring里使用AOP
在Spring
里,AOP
通过EnableAspectJAutoProxy
注解开启。默认情况下,Spring
会通过AopAutoConfiguration
自动引入这个注解
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
}
可以看到,如果我们不主动设置spring.aop.auto=false
。那么Spring
默认会启用AOP。接下来,我们可以通过在类上标注Aspect
即可使用AOP
package org.example.aspect;
@Aspect
@Component
public class SampleAspect {
@Pointcut("execution(* org.example.xxx.*.*(..))")
private void executionPointcut() {
}
@After(value = "executionPointcut()")
public void doAfter() {
}
}
源码分析
1. AOP初始化
1.1 初始化AspectJAutoProxyRegistrar
EnableAspectJAutoProxy
通过Import
注解引入了AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
}
AspectJAutoProxyRegistrar
实现了ImportBeanDefinitionRegistrar
,Spring
在初始化AopAutoConfiguration
时把所有通过Import
注解引入的ImportBeanDefinitionRegistrar
实现类拿出来进行初始化,并调用其registerBeanDefinitions
函数
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}
1.2 初始化AnnotationAwareAspectJAutoProxyCreator
AspectJAutoProxyRegistrar
则在registerBeanDefinitions
注册了一个AnnotationAwareAspectJAutoProxyCreator
的BeanDefinition
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
AnnotationAwareAspectJAutoProxyCreator
实现了BeanPostProcessor
,Spring
会在初始化普通Bean
之前初始化所有BeanPostProcessor
。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
// 初始化BeanProcessor来拦截Bean的创建
registerBeanPostProcessors(beanFactory);
// 初始化所有剩下的非懒加载的Bean,比如我们写的Service
finishBeanFactoryInitialization(beanFactory);
}
}
1.3 初始化切面方法跟切点
另外,AnnotationAwareAspectJAutoProxyCreator
实现了InstantiationAwareBeanPostProcessor
,Spring
会在Bean
创建时调用其postProcessBeforeInstantiation
方法对Bean
进行处理。
在第一次调用该方法时,AnnotationAwareAspectJAutoProxyCreator
会初始化切面
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
//判断当前BeanName对应的Bean是否应该被代理
//并将判断结果保存下来,避免后续的后处理方法重复计算
//在第一次判断时,会在shouldSkip里扫描所有Bean进行切面初始化
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put