AOP 简述
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在通过将横切关注点(cross-cutting concerns)从主业务逻辑中分离出来,以提高代码的模块化程度和可维护性。
比如日志记录、事务管理等功能与核心业务逻辑并不直接相关,AOP 旨在抽取这部分功能集中管理,避免了代码重复与散乱,实现了与业务逻辑的解耦。
Spring AOP 主要通过动态代理技术实现在目标对象前后添加额外的功能逻辑,完成对目标对象的增强。开发人员可以方便的使用Spring AOP 的各种注解完成对通用逻辑的抽取与业务扩展,下面以一个简单的日志打印功能举例说明,通过该切面类就可以实现对指定类的 controller 接口日志打印
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class.getName());
// 定义切入点,匹配com.example.api包下的所有Controller的public方法
@Pointcut("execution(public * com.example.api.controller..*(..))")
public void log() {}
// 环绕通知
@Around("log()")
public Object logApiCall(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String className = signature.getDeclaringType().getSimpleName();
String methodName = signature.getName();
Object[] args = joinPoint.getArgs();
// 打印方法调用前的日志
logger.info(String.format("Entering method: %s.%s with arguments: %s",
className, methodName, Arrays.toString(args)));
long startTime = System.currentTimeMillis();
// 执行目标方法
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
// 打印方法调用后的日志
logger.info(String.format("Exiting method: %s.%s with result: %s, execution time: %d ms",
className, methodName, result, (endTime - startTime)));
return result;
}
}
Spring AOP 核心概念
Spring AOP 使用了一系列通用的AOP概念,并基于不同的概念定义对应的接口和功能实现。下面主要简要介绍下AOP 的概念:
- 切面(Aspect):一个模块化的对象,它封装了横切关注点的逻辑。比如上面的日志切面类
LoggingAspect,它包含了连接点(joint Point) 与 通知(Advice) - **连接点(joint Point):**程序执行过程中的一个点,Spring AOP主要关注方法的连接点,即方法的执行。
- 通知(Advice):指切面在特定连接点上执行的动作,比如日志记录和事务管理或者其他自定义逻辑。根据执行前后顺序不同划分为以下几种类型
- 前置通知(Before):在连接点之前执行。
- 后置通知(After):在连接点之后执行,无论方法是否成功。
- 返回通知(AfterReturning):在方法成功返回后执行。
- 异常通知(AfterThrowing):在方法抛出异常后执行。
- 环绕通知(Around):包围连接点,可以在方法执行前后执行。
- **切点(Pointcut):**一个用于匹配连接点的表达式。它定义了哪些方法将被切面影响。Spring集成了 Aspecj 框架可以可以基于方法名、注解、参数等来定义表达式。上面例子中
execution(public * com.example.api.controller..*(..))表达式就是一个匹配所有controller方法的切点 - 目标对象(Target Object):指被一个或多个切面所通知的对象。
- 代理(AOP Proxy):由Spring AOP框架创建的对象,用于在不修改目标对象的情况下,将切面应用到目标对象上。Spring AOP默认使用JDK动态代理或CGLIB来创建代理。
Spring在实现AOP功能集成了 AspectJ 框架,但是Spring 并未完全使用AspectJ 框架的能力。Spring AOP主要采用动态代理的方式在运行时增强功能,并且仅支持方法级别的切面织入,但是SpringAOP支持使用 AspectJ 的注解定义切面,使得开发人员更加灵活的定义不同的切面对象。
针对上述这些概念 Spring AOP 分别定义了不同的接口与实现,这些接口是Spring实现 AOP 切面编程功能的核心,了解这些接口可以帮助开发人员更加清晰的掌握整个Spring AOP的实现原理与脉络。
Advice(通知)
- Advice 是一个标记接口,它不包含任何方法,仅仅用于标识一个对象是否是某种类型的增强处理,其子接口主要包含以下几种
MethodInterceptor:环绕增强(Around Advice)的接口,允许在方法执行前后和抛出异常时添加额外的行为。BeforeAdvice:前置增强(Before Advice)的接口,允许在方法执行之前添加额外的行为。AfterAdvice:后置增强(After Advice)的接口,允许在方法执行之后添加额外的行为,无论方法是否成功执行。AfterReturningAdvice:返回增强(After Returning Advice)的接口,允许在方法成功返回后添加额外的行为。ThrowsAdvice:异常增强(After Throwing Advice)的接口,允许在方法抛出异常后添加额外的行为。
PointCut(切点接口)
- 核心类,它定义了哪些连接点(通常是方法的执行)应该被通知(Advice)所增强,该接口定义了
ClassFilter与MethodMatcher实例获取方法,用于描述连接点。- ClassFilter(类过滤器接口):筛选指定类是否满足切点
- MethodMather(方法匹配器接口):判断方法是否满足切点
Advisor(通知器)
- 核心通知器接口,它维护了一个通知类,子接口需要通过指定拦截器表明该通知类的应用位置,Spring子接口主要包含
PointcutAdvisor: 切点通知器接口,该接口可以获取PointCut实例,表明哪些连接点应当通知增强IntroductionAdvisor: 引入通知器接口,该接口用于在运行时动态地给目标对象增加新的接口和方法,而无需修改原有类的代码,场景中维护了ClassFilter实例,表明该通知的应用位置。
TargetSource (目标源)
- 目标源接口主要作用提供代理对象使用的目标对象,并在允许在代理过程中动态切换目标。在不同作用域中的代理对象所获取的目标对象可能是不同的,比如原型(prototype)作用域目标对象。或者可以根据不同场景实现不同的目标源类型,Spring中默认实现接口
- PrototypeTargetSource:用于原型(prototype)的 Bean,每次请求时都会创建一个新的实例。
- SingletonTargetSource:用于单例的 Bean,整个应用程序生命周期内只有一个实例,spring默认实现。
- ThreadLocalTargetSource:将目标对象保存在 ThreadLocal 中,使得每个线程都有自己的目标对象实例。
- CommonsPool2TargetSource:使用 Apache Commons Pool 2 来管理目标对象的对象池
AopProxy(aop 代理类接口)
- 它定义了创建 AOP 代理对象的方法,Spring提供了两种类型的实现类,Spring默认使用JDK动态代理方式
- JdkDynamicAopProxy:使用 JDK 动态代理技术来创建代理对象
- CglibAopProxy:使用 CGLIB 库来创建代理对象
下以通俗的方式介绍下上述接口在Spring AOP中的主要作用
- Advice 以及相关子接口主要是对目标对象增强功能的抽象,即通用的扩展功能实现 What
- PointCut 它定义了哪些方法应该被 Advice 通知 所增强 Where
- Advisor 将通知与切点组合起来,即 What + Where
- TargetSource 是对目标对象的封装,主要用于获取目标对象,即 Who
- AopProxy AOP代理对象,将通知应用到目标源上,通过动态代理达到实现AOP增强,即 How
Spring AOP 实现原理的核心逻辑即通过动态代理的方式为目标对象创建代理对象,并根据不同的配置匹配到指定的切面对象,并集成封装到代理对象中。在执行目标对象的方法前后通过代理对象间接调用切面对象的增强方法,最终实现对目标对象的功能增强,最终实现切面编程的效果。
而上述接口在Spring AOP的实现过程中扮演着不同的角色,了解这部分内容可以让我们对Spring AOP 有一个更加清晰的了解。下面通过源码的方式剖析下其实现原理。
核心源码解析
Spring AOP是通过动态代理对象的方式完成,其本质就是对目标对象的扩展,即对 Bean 的扩展,因此Spring 使用 IOC 中的 BeanPostProcessor扩展点完成对Bean 的动态代理也是很容易联想到的。
AOP核心实现基类类 **AbstractAutoProxyCreator** 实现了BeanPostProcessor,并在 Bean initialize 阶段完成后通过创建代理对象实现功能增强。以下为该类继承图
ProxyConfig与ProxyProcessorSupport 类主要用于配置代理设置,实现 BeanPostProcessor 接口在bean 的初始化 initialize 阶段完成后进行动态代理即AOP实现。这里有两个特定的 BeanPostProcessor 子接口 分别是:
InstantiationAwareBeanPostProcessor:在BeanPostProcessorbean 的初始化扩展基础上额外扩展了 实例化前后扩展,针对在bean 的实力化前后完成扩展。AbstractAutoProxyCreator 实现该接口的实例化前扩展主要是为了解决自定义作用域的动态代理问题,比如 (prototype)作用域目标对象 或者 ThreadLocal 作用域对象的AOP增强。SmartInstantiationAwareBeanPostProcessor: AbstractAutoProxyCreator 实现了该接口的getEarlyBeanReference方法,主要是为了解决循环依赖时的动态代理问题。比如 A与B 实例相互依赖,假如实例 A 需要进行代理,则注入到 B 实例中时 A 实例 需要先进行动态代理生成代理对象,再将其注入到 B 实例中,相反一致。
下面简单通过源码解析下 AbstractAutoProxyCreator 的核心实现过程
AOP 核心实现流程
在 Bean 的初始化节点执行 BeanPostProcessor 的后置扩展,AbstractAutoProxyCreator作为实现类会执行后置扩展逻辑
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
...
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
...
if (mbd == null || !mbd.isSynthetic()) {
// 执行 BeanPostProcessor 后置初始化扩展方法
// 会执行AbstractAutoProxyCreator实例的postProcessAfterInitialization 方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
后置扩展实现中主要是判断是否需要进行动态代理,如果需要则获取所有的通知增强类并完成动态代理
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 判断当前实例是否需要增强
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取可以应用与当前 bean 的通知对象
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;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
总结核心执行链路
- Bean 实例初始化完成执行
AbstractAutoProxyCreator#postProcessAfterInitialization后置处理扩展 AbstractAutoProxyCreator#wrapIfNecessary判断是否需要对当前 Bean 生成代理对象AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean从Spring容器中获取可以应用到当前实例的通知增强对象,如日志记录切面或者事务拦截器等增强对象AbstractAutoProxyCreator#createProxy创建代理对象,并将通知对象封装到代理对象中,在执行代理对象方法时实现增强。
整体流程图示
所以这里的核心方法主要是 getAdvicesAndAdvisorsForBean 获取增强通知 与 createProxy 创建代理方法。
AbstractAutoProxyCreator
上述流程中的 getAdvicesAndAdvisorsForBean方法是 AbstractAutoProxyCreator提供的抽象模板方法,子类通过实现该方法定制化获取可应用与目标对象的 Advice 或者 Advisor 。下图为 AbstractAutoProxyCreator类继承图
首先介绍下两个抽象实现类 BeanNameAutoProxyCreator与 AbstractAdvisorAutoProxyCreator,两个抽象实现类均实现了父类的getAdvicesAndAdvisorsForBean 。
BeanNameAutoProxyCreator
该实现类并未设置获取特定的通知规则,仅通过 beanName 判断是否符合要求继续完成动态代理。方法实现源码如下
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
return (isSupportedBeanName(beanClass, beanName) ?
PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS : DO_NOT_PROXY);
}
private boolean isSupportedBeanName(Class<?> beanClass, String beanName) {
if (this.beanNames != null) {
boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass);
for (String mappedName : this.beanNames) {
if (isFactoryBean) {
if (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
continue;
}
mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
if (isMatch(beanName, mappedName)) {
return true;
}
}
BeanFactory beanFactory = getBeanFactory();
String[] aliases = (beanFactory != null ? beanFactory.getAliases(beanName) : NO_ALIASES);
for (String alias : aliases) {
for (String mappedName : this.beanNames) {
if (isMatch(alias, mappedName)) {
return true;
}
}
}
}
return false;
}
isSupportedBeanName 方法主要是根据目标实例的 beanName 与设置的 beanNames 属性通过简单的规则匹配判断是否符合代理条件,比如 符合 xxx* 以xxx开头的 bean 名称、*xxx 以xxx 结尾的 bean 名称均会被匹配。不同返回值含义如下:
- PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS 标识需要代理目标对象但不需要额外的拦截器
- DO_NOT_PROXY 标识不需要进行代理
AbstractAdvisorAutoProxyCreator
该类是一个通用的动态代理抽象类,各种动态代理创建类均继承该抽象类, 其getAdvicesAndAdvisorsForBean方法实现主要是获取不同的增强通知以及通知是否可以被应用到目标对象。
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 获取符合条件通知器
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取候选的通知器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 过滤获取可以应用于目标对象的通知器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List<Advisor> findCandidateAdvisors() {
// BeanFactoryAdvisorRetrievalHelper 检索所有通知器
return this.advisorRetrievalHelper.findAdvisorBeans();
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
方法实现逻辑主要包含两块内容:findCandidateAdvisors 获取所有候选通知器实例与 findAdvisorsThatCanApply 获取所有可以应用于目标对象的通知。
findCandidateAdvisors
findCandidateAdvisors方法通过 BeanFactoryAdvisorRetrievalHelper 类方法实现,该类的主要作用就是帮助检索 BeanFactory 中的 Advisor 实例。查看 BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans 方法源码
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 容器中获取所有 Advisor 接口实例
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)) {
...
advisors.add(this.beanFactory.getBean(name, Advisor.class));
...
}
}
return advisors;
}
该方法就是通过 IOC 容器获取所有的 Advisor 实例,然后通过 isEligibleBean 方法判断目标对象是否符合要求。
而这里的 isEligibleBean 方法其实真实调用的是 AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean 方法。其主要通过适配器模式转换调用方法,而 AbstractAdvisorAutoProxyCreator 子类可以在isEligibleAdvisorBean 基础上进行扩展。
private class BeanFactoryAdvisorRetrievalHelperAdapter extends BeanFactoryAdvisorRetrievalHelper {
...
@Override
protected boolean isEligibleBean(String beanName) {
return AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);
}
}
执行调用链如下图所示
两个实现子类实现根据场景覆盖了该方法
DefaultAdvisorAutoProxyCreator: 假如设置了前缀名匹配则会过滤特定名称前缀的 Advisor
protected boolean isEligibleAdvisorBean(String beanName) {
if (!isUsePrefix()) {
return true;
}
String prefix = getAdvisorBeanNamePrefix();
return (prefix != null && beanName.startsWith(prefix));
}
InfrastructureAdvisorAutoProxyCreator:仅筛选框架内部或基础设施相关的 Advisor,会忽略应用内部创建的 Advisor
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
findAdvisorsThatCanApply
findAdvisorsThatCanApply 是通过 AopUtils#findAdvisorsThatCanApply方法实现,该方法 的核心逻辑则是通过 AopUtils#canApply 实现。查看方法源码
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 通过 MethodMatcher 进行匹配筛选
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
该方法主要逻辑就是通过 Advisor 的 Pointcut 判断是否可以应用到目标实例的方法 Method 上,而判断规则是由 MethodMatcher实现。因此不同的 Pointcut实例可针对不同的场景实现自定义的匹配规则,也是 SpringAOP 的灵活之处,同样也体现了应该面向接口开发的优点。
AOP 动态代理实现类
AbstractAutoProxyCreator 实现了 AOP 的核心流程,提供了获取增强通知的的模板方法 getAdvicesAndAdvisorsForBean 供子类实现。而抽象继承类AbstractAdvisorAutoProxyCreator实现了该模板方法,可通过 IOC 容器获取 Advisor 实例。
下面介绍下具体实现类
-
DefaultAdvisorAutoProxyCreator:通用子类,它会自动为所有符合条件的 bean 创建 AOP 代理,假如设置了特定的前缀名则会过滤处理。 -
InfrastructureAdvisorAutoProxyCreator:主要用于框架内部或基础设施相关的代理创建,会忽略应用内部创建的 Advisor -
AspectJAwareAdvisorAutoProxyCreator:专门用于AspectJ 风格的切面定义 -
AnnotationAwareAspectJAutoProxyCreator:AspectJAwareAdvisorAutoProxyCreator子类,支持 AspectJ 注解的定义,会自动检测并应用带有@Aspect注解的切面实例。上文中的日志切面例子即使用的该代理创建类。
关于 Spring AOP 注解实现原理
Spring 支持通过使用 AspectJ 注解的方式配置切面,比如上文 demo 中的日志切面 LoggingAspect 就是一个简单的使用例子。SpringAOP 实现的核心源码上文已经简单介绍过了,而 Spring 是如何解析切面实例,并如何将各种注解方法生成增强通知的?
AnnotationAwareAspectJAutoProxyCreator类就是实现 AspectJ 注解切面的核心类。它继承自 AbstractAdvisorAutoProxyCreator 类,通过重写了父类的 findCandidateAdvisors方法使其不仅拥有通过容器获取实例的能力,并且会自动检测并应用带有 @Aspect 注解的切面实例。
@Override
protected List<Advisor> findCandidateAdvisors() {
// 通过父类 AbstractAdvisorAutoProxyCreator 获取容器中的 Advisor
List<Advisor> advisors = super.findCandidateAdvisors();
// 构建所有在容器中的 AspectJ 切面实例
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
解析 @Aspect并生成切面则是由 BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors方法实现。
解析切面 BeanFactoryAspectJAdvisorsBuilder
BeanFactoryAspectJAdvisorsBuilder类的主要作用就是解析切面配置类 Aspect,并将切面实例中的方法包装成对应的通知。源码方法如下
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
// 过滤不符合要求的 bean
// 最终调用的 AnnotationAwareAspectJAutoProxyCreator#isEligibleAspectBean方法
if (!isEligibleBean(beanName)) {
continue;
}
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 判断该类是否存在 @Aspect 切面注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 单例 or 多实例切面
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 解析切面实例,生成通知
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// 解析切面实例,生成通知
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) {
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;
}
该方法的核心流程
-
- 从 BeanFactory 中获取所有 bean
-
- 调用 isEligibleBean 方法(间接调用的 AnnotationAwareAspectJAutoProxyCreator#isEligibleAspectBean方法)过滤不符合要求的 bean
-
- 判断 bean class 是否为切面(aspect)bean
-
- 根据切面 bean 生成对应的 Advisor 实例,并将其缓存以供下次执行获取
第三步与第四步的功能由 AspectJAdvisorFactory 接口实现类 ReflectiveAspectJAdvisorFactory完成。
生成通知 ReflectiveAspectJAdvisorFactory
ReflectiveAspectJAdvisorFactory 主要提供两个能力:
isAspect:通过解析给定 bean class 是否存在Aspect注解判断是否为切面类
public boolean isAspect(Class<?> clazz) {
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
getAdvisors: 通过切面类元数据生成增强通知实例,切面类元数据通过MetadataAwareAspectInstanceFactory工厂类解析获取
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 获取通知类所有方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 根据 Method 生成 Advisor 通知实例
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
...
return advisors;
}
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 解析 AspectJ 表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 创建通知
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
InstantiationModelAwarePointcutAdvisorImpl在构造执行阶段通过 ReflectiveAspectJAdvisorFactory#getAdvice 将切面对象的 Method 转换为 Advice ,通过
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
...
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
...
}
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
下面为最终创建通知的方法,根据方法上不同注解类型比如@Around、@Before 、@After等,生成不同的通知类 Advice,到此为止就完成了 Aspect 注解切面实例的通知解析。
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
...
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
...
return springAdvice;
}
核心原理总结
Spring 容器在 Bean Initiate 初始化阶段执行 BeanPostprocessor#postProcessAfterInitialization,而AbstractAutoProxyCreator 作为实现类,会符合条件的 Bean 进行动态代理,并提供 getAdvicesAndAdvisorsForBean的抽象模版方法。
AbstractAdvisorAutoProxyCreator 实现了该抽象方法,通过 BeanFactory 获取 Advisor 实例并判断是否可以应用到目标 Bean 上。
AnnotationAwareAspectJAutoProxyCreator 重写了AbstractAdvisorAutoProxyCreator 的 getAdvicesAndAdvisorsForBean 方法,支持使用了 AspectJ 注解切面实例的解析。
解析过程如下:
-
- 从 BeanFactory 中获取所有符合要求的
@Aspect切面实例,BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
- 从 BeanFactory 中获取所有符合要求的
-
- 将切面实例中的方法转换为 Advisor 实例
ReflectiveAspectJAdvisorFactory#getAdvisor创建InstantiationModelAwarePointcutAdvisorImpl对象,该类是由 Spring 实现的 Advisor 默认实现类 。InstantiationModelAwarePointcutAdvisorImpl在构造阶段将切面实例中使用了@Around、@Before、@After等注解的方法封装为 Advice 对象