这篇介绍了BeanPostProcessor
的注册,这篇介绍了BeanPostProcessor
的调用,接下来看一下Spring boot 中 AOP 相关的基础 BeanPostProcessor
。
一、自动配置
注册基础的BeanDefinition
:
- 模块:
spring-boot-autoconfigure
- 基础包:
org.springframework.boot.autoconfigure
- AOP相关的包:
org.springframework.boot.autoconfigure.aop
二、AopAutoConfiguration
1.源码
/**
* AopAutoConfiguration 是 Spring Boot 自动配置的一部分,用于启用 Spring AOP 支持。
* 等价于在配置中手动添加 @EnableAspectJAutoProxy 注解。
*
* <p>如果配置项 spring.aop.auto=false,则不会激活此自动配置。</p>
* <p>默认情况下,会使用基于类的代理(proxyTargetClass = true),
* 但可以通过设置 spring.aop.proxy-target-class=false 来覆盖这一行为。</p>
*
* @author Dave Syer
* @author Josh Long
* @since 1.0.0
* @see EnableAspectJAutoProxy
*/
// 启用 Spring Boot 的自动配置机制
@AutoConfiguration
// 条件注解:只有当配置属性 spring.aop.auto 为 true(或不存在时,默认匹配)才会加载该配置
@ConditionalOnBooleanProperty(name = "spring.aop.auto", matchIfMissing = true)
public class AopAutoConfiguration {
/**
* 当类路径下存在 org.aspectj.weaver.Advice 时,
* 表示项目引入了 AspectJ 类库,将启用基于 AspectJ 的 AOP 自动代理配置。
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
/**
* 当配置项 spring.aop.proxy-target-class=false 时,
* 使用 JDK 动态代理来创建代理对象。
*/
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", havingValue = false)
static class JdkDynamicAutoProxyConfiguration {
}
/**
* 当配置项 spring.aop.proxy-target-class=true 或未配置时(matchIfMissing = true),
* 使用 CGLIB 代理来创建代理对象(基于类的代理)。
*/
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
/**
* 如果类路径下没有 org.aspectj.weaver.Advice 类(即未引入 AspectJ),
* 并且配置项 spring.aop.proxy-target-class 为 true 或未配置,
* 则进入此配置类,强制使用基于类的代理方式。
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnBooleanProperty(name = "spring.aop.proxy-target-class", matchIfMissing = true)
static class ClassProxyingConfiguration {
/**
* 定义一个静态 Bean,类型为 BeanFactoryPostProcessor,
* 强制 Spring 使用基于类的代理方式(即使目标类没有实现接口)。
*/
@Bean
static BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {
return (beanFactory) -> {
if (beanFactory instanceof BeanDefinitionRegistry registry) {
// 注册自动代理创建者(如果尚未注册)
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
// 强制使用基于类的代理
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
};
}
}
}
说明:
AopAutoConfiguration
是 Spring Boot 中用于自动配置 AOP 的核心类。- 满足条件
@ConditionalOnClass(Advice.class)
,根据配置参数spring.aop.proxy-target-class
决定使用 JDK 动态代理 还是 CGLIB 代理。 - 满足条件
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
,Spring 会通过自定义一个BeanFactoryPostProcessor
注册自动代理创建者。
三、@EnableAspectJAutoProxy
1.源码
/**
* <b>注意</b>:{@code @EnableAspectJAutoProxy} 只对其所在的应用上下文(ApplicationContext)生效,
* 这样可以让你在不同层级选择性地启用代理功能。如果你希望在整个应用的不同层级都启用该功能,
* 比如根 Web 应用上下文(root web application context)和多个独立的 {@code DispatcherServlet}
* 所属的子上下文(child contexts),你需要在每个上下文中单独声明此注解。
*
* <p>使用这个功能要求类路径中包含 {@code aspectjweaver} 依赖。
* 虽然对于整个 {@code spring-aop} 来说,这个依赖是可选的,
* 但对于 {@code @EnableAspectJAutoProxy} 注解及其底层机制来说,它是必须的。
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see org.aspectj.lang.annotation.Aspect
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class) // 导入配置类,用于注册 AOP 相关组件
public @interface EnableAspectJAutoProxy {
/**
* 设置是否创建基于子类(CGLIB)的代理对象,而不是默认的基于接口的 JDK 动态代理。
* 默认值为 false,表示优先使用 JDK 动态代理。
*/
boolean proxyTargetClass() default false;
/**
* 设置是否将生成的代理对象暴露给 AOP 框架,以便通过
* {@link org.springframework.aop.framework.AopContext} 类进行访问。
* 默认关闭,即不能保证可以通过 AopContext 获取当前代理对象。
*
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
📌 说明
内容 | 说明 |
---|---|
作用 | 启用对 @Aspect 注解切面的支持,等价于 XML 配置中的 <aop:aspectj-autoproxy/> |
核心注解 | @Import(AspectJAutoProxyRegistrar.class) ,导入自动代理创建逻辑 |
proxyTargetClass | 控制使用 CGLIB 代理(true)还是 JDK 动态代理(false,默认) |
exposeProxy | 控制是否将代理对象暴露给 ThreadLocal ,方便在 Advice 中通过 AopContext.currentProxy() 获取 |
注意事项 | 必须引入 aspectjweaver 依赖才能支持注解风格的切面 |
使用方式 | 通常与 @Configuration 配合使用,在 Java 配置类上标注 |
2.AspectJAutoProxyRegistrar
/**
* 根据给定的 @{@link EnableAspectJAutoProxy} 注解配置,
* 在当前的 {@link BeanDefinitionRegistry} 中注册一个
* {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator}
* 实例。
*
* <p>该类用于支持基于注解风格的 AOP 自动代理创建器(AnnotationAwareAspectJAutoProxyCreator),
* 通常由 @{@link EnableAspectJAutoProxy} 注解导入使用。
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see EnableAspectJAutoProxy
*/
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* 根据导入该注册器的 @{@link Configuration} 类上定义的
* @{@link EnableAspectJAutoProxy#proxyTargetClass()} 属性值,
* 来注册、升级并配置 AspectJ 自动代理创建器。
*
* <p>主要完成以下工作:
* 1. 注册 AnnotationAwareAspectJAutoProxyCreator(如果尚未注册)
* 2. 如果启用了 proxyTargetClass = true,则强制使用 CGLIB 代理
* 3. 如果启用了 exposeProxy = true,则将代理对象暴露给 ThreadLocal 上下文
*
* @param importingClassMetadata 导入该注册器的类的注解元数据
* @param registry BeanDefinition 注册表,用于注册自动代理创建器
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 注册或升级为支持 @Aspect 注解切面的自动代理创建器
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 获取 @EnableAspectJAutoProxy 注解上的属性值
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
// 如果存在该注解,则根据其属性进一步配置自动代理行为
if (enableAspectJAutoProxy != null) {
// 如果设置了 proxyTargetClass = true,则强制使用 CGLIB 子类代理
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 如果设置了 exposeProxy = true,则将代理对象暴露给 ThreadLocal 上下文
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
📌 说明
内容 | 描述 |
---|---|
作用 | 用于在 Spring 容器中注册和配置 AnnotationAwareAspectJAutoProxyCreator |
触发方式 | 被 @EnableAspectJAutoProxy 注解通过 @Import 引入 |
核心逻辑 | - 注册 AOP 自动代理创建器 - 支持 proxyTargetClass 配置 - 支持 exposeProxy 配置 |
相关类 | - @EnableAspectJAutoProxy - AopConfigUtils - AnnotationAwareAspectJAutoProxyCreator |
四、AopConfigUtils
1.源码
/**
* AOP 自动代理创建器(AutoProxyCreator)的注册工具类。
*
* <p>Spring AOP 中存在多个不同能力的 AutoProxyCreator 实现类:
* - InfrastructureAdvisorAutoProxyCreator:最基础,仅处理 ROLE_INFRASTRUCTURE 的 Advisor
* - AspectJAwareAdvisorAutoProxyCreator:支持 AspectJ 表达式和规则
* - AnnotationAwareAspectJAutoProxyCreator:功能最强大,支持 @Aspect 注解风格切面
*
* 该工具类提供一个“升级协议”,确保当你请求注册某个 AutoProxyCreator 时,
* 如果已经存在其他实现,则会根据优先级决定是否替换为更高级别的版本。
*
* @author Rob Harrop
* @author Juergen Hoeller
* @author Mark Fisher
* @since 2.5
*/
public abstract class AopConfigUtils {
/**
* Spring 内部管理的自动代理创建器 Bean 的名称。
* 这个 Bean 是 Spring 容器中负责生成 AOP 代理的核心组件。
*/
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
/**
* 存储不同 AutoProxyCreator 类的优先级顺序。
* 列表越靠后的类,功能越强,优先级越高。
*/
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// 初始化优先级排序:
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); // 最基础
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); // 支持 AspectJ 表达式
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); // 支持 @Aspect 注解切面
}
/**
* 必要时注册最基础的 AutoProxyCreator。
* 若容器中已有更高优先级的 AutoProxyCreator,则不会重复注册。
*/
public static @Nullable BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
/**
* 必要时注册最基础的 AutoProxyCreator,并指定配置源对象。
*/
public static @Nullable BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
/**
* 必要时注册支持 AspectJ 风格表达式的 AutoProxyCreator。
* 若已有更高优先级的实现,则不会重复注册。
*/
public static @Nullable BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAutoProxyCreatorIfNecessary(registry, null);
}
/**
* 必要时注册支持 AspectJ 风格表达式的 AutoProxyCreator,并指定配置源对象。
*/
public static @Nullable BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
/**
* 必要时注册支持 @Aspect 注解风格切面的 AutoProxyCreator。
* 这是目前功能最全面、推荐使用的实现。
*/
public static @Nullable BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
/**
* 必要时注册支持 @Aspect 注解风格切面的 AutoProxyCreator,并指定配置源对象。
*/
public static @Nullable BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
/**
* 强制 AutoProxyCreator 使用 CGLIB 来代理目标类(即使目标类实现了接口)。
*/
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
/**
* 强制 AutoProxyCreator 将当前代理对象暴露给 ThreadLocal。
* 可用于在 Advice 中获取当前代理实例。
*/
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
/**
* 注册或升级 AOP 自动代理创建器(AutoProxyCreator)。
*
* 此方法用于在 BeanDefinitionRegistry 中注册指定类型的自动代理创建器 bean,
* 如果已存在其他类型的自动代理创建器,则根据优先级决定是否替换它。
*
* @param cls 要注册的自动代理创建器类(如 InfrastructureAdvisorAutoProxyCreator.class)
* @param registry 用来注册 BeanDefinition 的注册表
* @param source 配置源对象(可选),用于调试或日志记录
* @return 如果新注册了该类型 bean 定义,则返回对应的 BeanDefinition;
* 如果只是升级了现有定义或已有相同类型 bean,则返回 null
*/
private static @Nullable BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls,
BeanDefinitionRegistry registry,
@Nullable Object source) {
// 参数校验,确保 registry 不为 null
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 检查容器中是否已经存在名为 internalAutoProxyCreator 的 bean 定义
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
// 获取当前存在的自动代理创建器的 BeanDefinition
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 如果当前存在的类名和要注册的类不同,说明需要判断是否进行替换
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
// 获取当前定义的自动代理创建器的优先级
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
// 获取即将注册的新类的优先级
int requiredPriority = findPriorityForClass(cls);
// 如果新类优先级更高,则更新为新的类名
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
// 如果已经存在一个定义,并且不需要替换,则直接返回 null
return null;
}
// 如果不存在,则创建一个新的 RootBeanDefinition 实例
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
// 设置配置源(用于调试信息)
beanDefinition.setSource(source);
// 设置顺序属性为最高优先级,保证该后处理器最早执行
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
// 标记此 bean 定义为基础设施 bean(不会被用户直接使用)
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 将新定义的自动代理创建器注册到容器中
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
// 返回新创建的 BeanDefinition
return beanDefinition;
}
/**
* 获取指定类在优先级列表中的索引值(索引越小优先级越低)。
*/
private static int findPriorityForClass(Class<?> clazz) {
return APC_PRIORITY_LIST.indexOf(clazz);
}
/**
* 获取指定类名字符串在优先级列表中的索引值。
* 如果未找到,抛出异常。
*/
private static int findPriorityForClass(@Nullable String className) {
for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
Class<?> clazz = APC_PRIORITY_LIST.get(i);
if (clazz.getName().equals(className)) {
return i;
}
}
throw new IllegalArgumentException(
"Class name [" + className + "] is not a known auto-proxy creator class");
}
}
说明
- order:设置BeanDefinition的
order
为最高优先级,保证该后处理器最早执行 - 优先级顺序:
InfrastructureAdvisorAutoProxyCreator
<AspectJAwareAdvisorAutoProxyCreator
<AnnotationAwareAspectJAutoProxyCreator
2. 🔍3个AutoProxyCreator
比较
功能/能力 | InfrastructureAdvisorAutoProxyCreator | AspectJAwareAdvisorAutoProxyCreator | AnnotationAwareAspectJAutoProxyCreator |
---|---|---|---|
仅处理 ROLE_INFRASTRUCTURE 的 Advisor | ✅ | ✅ | ✅ |
支持 XML 配置的 AspectJ 切面 | ❌ | ✅ | ✅ |
支持 @Aspect 、@Pointcut 、@Before 等注解 | ❌ | ❌ | ✅ |
支持 AspectJ 表达式(execution, within 等) | ❌ | ✅ | ✅ |
支持切面排序(按声明顺序) | ❌ | ✅ | ✅ |
是否支持 <aop:include> 过滤 | ❌ | ❌ | ✅ |
是否自动识别 @Aspect 类 | ❌ | ❌ | ✅ |
优先级 | 0 | 1 | 2 |
五、AbstractAutoProxyCreator
1. 简介
- 3个
AutoProxyCreator
都继承AbstractAutoProxyCreator
- 实现
BeanPostProcessor
2. getEarlyBeanReference(...)
方法
/**
* 获取早期 Bean 引用,并决定是否对其进行包装(即创建代理对象)。
*
* <p>该方法是 Spring 解决循环依赖机制中的一个重要环节,同时也用于提前为 Bean 创建 AOP 代理。
* 当一个 Bean 被放入三级缓存中用于解决循环引用时,会调用此方法获取其早期引用(early reference)。
*
* <p>具体来说:
* - 将当前 Bean 放入 earlyBeanReferences 缓存中,标识它是一个早期 Bean
* - 然后调用 wrapIfNecessary 方法判断是否需要为该 Bean 创建代理对象
*
* @param bean 正在被处理的 Bean 实例(尚未完全初始化)
* @param beanName 该 Bean 在容器中的名称
* @return 返回原始 Bean 或其代理对象
*/
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 构建缓存键,用于唯一标识当前 Bean 的类型和名称
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 将当前 Bean 添加到 earlyBeanReferences 缓存中,表示这是一个早期 Bean 引用
// 放入的是原始 Bean 实例
this.earlyBeanReferences.put(cacheKey, bean);
// 判断是否需要对当前 Bean 进行代理包装
return wrapIfNecessary(bean, beanName, cacheKey);
}
📌 执行时机
- 出现循环依赖,详见这篇
📌 方法逻辑
步骤 | 功能说明 |
---|---|
1 | 构建缓存键(cacheKey):用于唯一标识当前 Bean 的 Class 和 Name |
2 | 记录早期 Bean 引用:将当前 Bean(原始 Bean 实例)存入 earlyBeanReferences 缓存,用于后续判断是否已被处理过 |
3 | 尝试包装 Bean:调用 wrapIfNecessary() 方法,判断并返回该 Bean 的代理对象 或者 原始对象 |
📚 关联方法
-
getCacheKey(Class<?> beanClass, String beanName)
根据 Bean 的类和名称生成用于缓存的 key。
-
earlyBeanReferences
缓存用于存储早期 Bean 引用,避免重复代理和帮助解决循环依赖。
-
wrapIfNecessary(...)
核心代理创建逻辑:判断是否要代理该 Bean,并返回代理对象 或者 原始对象。
📝 小结
内容 | 说明 |
---|---|
作用 | 在 Bean 初始化完成前提供早期引用,并决定是否为其创建 AOP 代理 |
应用场景 | - 循环依赖处理 - 提前进行 AOP 代理(如在其他 Bean 依赖它时) |
核心行为 | - 记录 Bean 的早期引用 - 调用 wrapIfNecessary() 方法创建代理(如有需要) |
关键机制 | 与 Spring 的三级缓存配合,实现延迟代理创建与循环依赖解决 |
3. postProcessBeforeInstantiation(...)
方法
/**
* 在目标 Bean 实例化之前被调用,用于判断是否需要为该 Bean 创建代理对象。
*
* <p>该方法是 Spring AOP 中实现自动代理的核心逻辑之一。它在 Spring 容器创建 Bean 实例之前执行,
* 如果在此阶段返回一个代理对象,则容器将直接使用该代理对象,而不再继续创建原始 Bean 实例。
*
* <p>此方法主要处理以下两种情况:
* 1. 是否跳过当前 Bean(如基础设施类或配置中指定跳过的类)
* 2. 是否存在自定义 TargetSource,若存在则提前创建代理对象
*
* @param beanClass 要实例化的 Bean 的 Class 对象
* @param beanName 要实例化的 Bean 的名称
* @return 如果需要创建代理,则返回代理对象;否则返回 null,表示继续按正常流程创建 Bean
*/
@Override
public @Nullable Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 构建缓存键,用于标识当前 Bean 的类型和名称
Object cacheKey = getCacheKey(beanClass, beanName);
// 如果没有提供 beanName 或者该 bean 不是通过自定义 TargetSource 创建的,
// 则检查是否已经处理过该 Bean 的代理状态
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 如果已经记录了该 Bean 的代理状态,则直接返回 null,不再处理
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 如果是基础设施类(如 Advice、Advisor 等)或者应该跳过代理的类,则标记为不需要代理并返回 null
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 如果有自定义的 TargetSource(目标源),则在此阶段创建代理对象
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
// 记录该 bean 是由自定义 TargetSource 创建的
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 获取适用于当前 Bean 的特定拦截器(Advice/Advisor)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 创建代理对象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 缓存代理类的类型信息
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理对象,阻止 Spring 继续创建原始 Bean 实例
return proxy;
}
// 没有自定义 TargetSource,继续走正常的 Bean 实例化流程
return null;
}
📌 说明
步骤 | 功能说明 |
---|---|
1 | 构建缓存键(cacheKey):用于唯一标识当前正在处理的 Bean |
2 | 是否已处理过该 Bean:如果已在 advisedBeans 中记录其是否需要代理,则直接返回结果 |
3 | 判断是否跳过代理:如是基础设施类(如 Advisor、Advice)或子类决定跳过(shouldSkip),则标记为 FALSE 并返回 null |
4 | 尝试获取自定义 TargetSource:如果存在自定义的目标源,则准备为其创建代理 |
5 | 获取适用于该 Bean 的拦截器链(specificInterceptors) |
6 | 创建代理对象:通过createProxy() 方法生成 AOP 代理 |
7 | 缓存代理类类型,避免重复处理 |
8 | 返回代理对象,Spring 将不会继续创建原始 Bean 实例 |
📚 关键方法
-
getCacheKey(beanClass, beanName)
生成用于缓存的 key,优先使用 beanName,必要时使用 class。
-
isInfrastructureClass(beanClass)
判断是否是基础设施类(如 Advice、Pointcut、Advisor、AopInfrastructureBean),这些类不应该被代理。
-
shouldSkip(beanClass, beanName)
子类可重写此方法以决定某些 Bean 是否应跳过代理(例如为了避免循环依赖)。
-
getCustomTargetSource(beanClass, beanName)
获取用户自定义的目标源(TargetSource),如池化、原型等特殊场景下使用。
-
getAdvicesAndAdvisorsForBean(...)
抽象方法,子类必须实现,用于获取适用于当前 Bean 的拦截器链。
-
createProxy(...)
使用 ProxyFactory 创建 AOP 代理对象。
4. postProcessAfterInitialization(...)
方法
/**
* 在目标 Bean 初始化完成后被调用,用于决定是否为其创建 AOP 代理对象。
*
* <p>该方法是 Spring AOP 中实现自动代理的关键步骤之一。它在 Bean 的所有属性设置和初始化方法(如 init-method)
* 执行之后被调用。如果在此阶段返回一个代理对象,则容器将使用该代理对象替代原始 Bean 实例。
*
* <p>此方法主要完成以下任务:
* 1. 检查当前 Bean 是否已经被提前代理(early proxying),例如在 {@link #postProcessBeforeInstantiation} 阶段
* 2. 如果未被提前代理,则根据配置判断是否需要为当前 Bean 创建代理
*
* @param bean 初始化完成后的原始 Bean 实例
* @param beanName 该 Bean 在容器中的名称
* @return 如果需要代理,返回包装后的代理对象;否则返回原始 Bean 实例
*/
@Override
public @Nullable Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
// 如果 bean 不为空
if (bean != null) {
// 构建缓存键,用于唯一标识当前 Bean 的类型和名称
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 从 earlyBeanReferences 缓存中移除该 bean,判断是否是早期代理的对象
// 如果不是早期代理的对象,则执行 wrapIfNecessary 方法尝试创建代理
if (this.earlyBeanReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
// 返回原始 bean 对象(无需代理)
return bean;
}
📌 入参bean
- 没有出现
循环依赖
:为原始对象 - 出现
循环依赖
:调用getEarlyBeanReference(...)
方法,再调用wrapIfNecessary(...)
方法,此时的 bean 为 代理对象 或者 原始对象
📌 说明
步骤 | 功能说明 |
---|---|
1 | 检查 bean 是否为 null:若为 null 则直接返回,不做处理 |
2 | 构建缓存键(cacheKey):用于唯一标识当前 Bean 的 Class 和 Name |
3 | 从 earlyBeanReferences 中移除 cacheKey 对应的对象: - 若移除的值与当前 bean 不同,需要进行代理处理 |
4 | 调用 wrapIfNecessary() 方法:实际创建代理对象的核心逻辑 |
5 | 返回代理或原始 bean |
📚 关键方法
-
getCacheKey(bean.getClass(), beanName)
生成用于缓存的 key,优先使用 beanName,必要时使用 class。
-
wrapIfNecessary(bean, beanName, cacheKey)
核心代理创建逻辑:判断是否需要代理、获取拦截器链、创建代理对象等。
-
earlyBeanReferences
存储早期 Bean 引用的缓存,用于解决循环依赖及避免重复代理。
📝 小结
内容 | 说明 |
---|---|
作用 | 在 Bean 初始化完成后决定是否为其创建 AOP 代理对象 |
执行时机 | Bean 的 afterPropertiesSet() 或自定义 init-method 调用之后 |
关键逻辑 | - 判断是否已在实例化前创建过代理 - 若未提前代理,则调用 wrapIfNecessary() 创建代理 |
核心方法 | wrapIfNecessary() |
子类扩展点 | getAdvicesAndAdvisorsForBean(...) :子类必须实现该抽象方法来决定哪些 Bean 需要被代理 |
5. getCacheKey(...)
方法
/**
* 为给定的 Bean 类型和名称构建一个缓存键(cache key),用于唯一标识该 Bean。
*
* <p>该方法用于在缓存中存储与 Bean 相关的信息(如代理类型、是否已被代理等)时使用。
* 从 Spring 4.2.3 开始,该实现不再返回将类名和 Bean 名拼接的字符串,
* 而是采用更高效的策略生成缓存键:
* - 如果提供了 beanName,则直接使用 beanName;
* - 若该 Bean 是 FactoryBean 类型,则在其 beanName 前添加 {@link BeanFactory#FACTORY_BEAN_PREFIX} 前缀;
* - 如果没有提供 beanName,则直接使用 beanClass 作为缓存键。
*
* @param beanClass 当前 Bean 的 Class 对象
* @param beanName 当前 Bean 在容器中的名称(可能为 null)
* @return 返回用于缓存的键对象,可以是 String 或 Class 类型
*/
protected Object getCacheKey(Class<?> beanClass, @Nullable String beanName) {
// 如果提供了 beanName,则基于 beanName 构建缓存键
if (StringUtils.hasLength(beanName)) {
// 如果该 Bean 是 FactoryBean 类型,则加上 FACTORY_BEAN_PREFIX 前缀
// 例如:beanName 为 "myBean",且是 FactoryBean,则返回 "&myBean"
return (FactoryBean.class.isAssignableFrom(beanClass) ?
BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
}
else {
// 如果没有提供 beanName,则直接以 Class 作为缓存键
return beanClass;
}
}
6. wrapIfNecessary(...)
方法
/**
* 如果需要,包装给定的 bean,即如果该 bean 有资格被代理,则为其创建 AOP 代理。
*
* @param bean 原始的 bean 实例
* @param beanName bean 的名称
* @param cacheKey 用于元数据访问的缓存键(通常是类或 bean 名称的组合)
* @return 如果需要代理,则返回代理对象;否则返回原始 bean 实例
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果 beanName 存在,并且该 bean 已经由自定义 TargetSource 创建,则不需要再代理
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果该 bean 被标记为不需要代理(advisedBeans 中值为 false),直接返回原对象
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 判断当前 bean 是否是基础设施类(如 Advice、Pointcut、Advisor 等),或者是否应该跳过代理处理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取适用于该 bean 的特定拦截器(advice 或 advisor)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果有需要应用的拦截器,则创建代理对象
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 使用 SingletonTargetSource 包装原始 bean
// 创建代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 缓存代理类的类型
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理对象
return proxy;
}
// 如果没有需要应用的拦截器,则标记为不代理,并返回原始 bean
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
说明:
- 该方法负责判断一个 bean 是否需要被 AOP 代理。
- 如果需要代理,则调用
createProxy
创建代理对象。 - 各种条件判断用于避免重复代理、跳过基础设施类、以及根据业务逻辑决定是否代理。
- 通过
getAdvicesAndAdvisorsForBean
获取适用于该 bean 的切面逻辑(拦截器链)。
注:该方法是 Spring AOP 自动代理机制的核心流程之一,常用于
postProcessAfterInitialization
阶段对符合条件的 bean 进行代理封装。
7. getAdvicesAndAdvisorsForBean(...)
方法
一个抽象方法,用于决定是否需要为指定的 Bean 创建代理,并提供适用于该 Bean 的拦截器(Advice)和通知器(Advisor)。
/**
* 判断给定的 Bean 是否需要被代理,以及需要应用哪些额外的通知(例如 AOP Alliance 拦截器)和通知器。
*
* @param beanClass 需要进行增强的 Bean 的类对象
* @param beanName 需要进行增强的 Bean 的名称
* @param customTargetSource 由 {@link #getCustomTargetSource} 方法返回的 TargetSource 对象,
* 如果没有使用自定义 TargetSource,则为 null。
* @return 返回适用于该 Bean 的额外拦截器数组;如果不需要额外的拦截器,仅使用公共拦截器,则返回空数组;
* 如果不需要代理(包括不使用公共拦截器),则返回 null。
* 可以参考常量 DO_NOT_PROXY 和 PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS。
* @throws BeansException 如果在获取拦截器或通知器过程中发生错误
* @see #DO_NOT_PROXY
* @see #PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
*/
protected abstract Object @Nullable [] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
@Nullable TargetSource customTargetSource) throws BeansException;
说明:
- 功能:此方法用于确定目标 Bean 是否需要被代理。如果需要,它还负责返回适用于该 Bean 的一组拦截器和通知器。
- 参数:
beanClass
:当前正在处理的目标 Bean 的类对象。beanName
:目标 Bean 在 Spring 容器中的名称。customTargetSource
:可选的自定义目标源,通常由getCustomTargetSource
方法生成。如果没有自定义目标源,则传入null
。
- 返回值:
Object[]
:包含额外的拦截器和通知器的对象数组。- 如果返回
null
,表示不创建代理(即使有公共拦截器)。 - 如果返回空数组
PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
,表示需要创建代理,但只使用公共拦截器。 - 如果返回非空数组,表示需要创建代理,并且将数组中的拦截器与公共拦截器一起应用。
- 如果返回
- 异常:
BeansException
:当加载拦截器或通知器失败时抛出异常。
使用场景:
该方法是一个模板方法
,供子类实现具体的代理逻辑。不同的子类可以基于不同的策略(如根据 Bean 名称、类型、注解等)来决定是否对某个 Bean 进行代理,并提供相应的拦截器和通知器。例如:
BeanNameAutoProxyCreator
:通过匹配 Bean 名称来决定是否代理。AbstractAdvisorAutoProxyCreator
:根据Advisor
的切点(Pointcut
)动态匹配目标 Bean 来决定是否代理。
8. createProxy(...)
方法
/**
* 为指定的 Bean 创建 AOP 代理对象。
*
* @param beanClass 被代理的目标类
* @param beanName Bean 的名称
* @param specificInterceptors 特定于该 Bean 的拦截器数组(可以为空,但不能为 null)
* @param targetSource 目标源对象,用于获取目标实例
* @return 返回创建好的 AOP 代理对象
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
Object @Nullable [] specificInterceptors, TargetSource targetSource) {
return buildProxy(beanClass, beanName, specificInterceptors, targetSource, false);
}
/**
* 仅生成代理类的 Class 对象,而不是实例。
*/
private Class<?> createProxyClass(Class<?> beanClass, @Nullable String beanName,
Object @Nullable [] specificInterceptors, TargetSource targetSource) {
return (Class<?>) buildProxy(beanClass, beanName, specificInterceptors, targetSource, true);
}
/**
* 构建 AOP 代理的核心方法。
*
* @param beanClass 被代理的目标类
* @param beanName Bean 名称
* @param specificInterceptors 特定拦截器(如切面、通知等)
* @param targetSource 目标对象来源
* @param classOnly 是否只生成 Class 对象而不创建实例
* @return 如果 classOnly 为 true,返回代理类;否则返回代理实例
*/
private Object buildProxy(Class<?> beanClass, @Nullable String beanName,
Object @Nullable [] specificInterceptors, TargetSource targetSource, boolean classOnly) {
// 暴露目标类信息给容器(用于调试或日志记录)
if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) {
AutoProxyUtils.exposeTargetClass(clbf, beanName, beanClass);
}
// 创建 ProxyFactory 并复制当前配置
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 如果强制使用 CGLIB 代理(proxyTargetClass == true)
if (proxyFactory.isProxyTargetClass()) {
// 如果是 JDK 动态代理生成的类或 Lambda 表达式,则添加其所有接口以支持引入增强
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// 否则根据默认策略决定是否使用 CGLIB 或 JDK 动态代理
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 构建 Advisor 数组(包括通用和特定的拦截器)
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory); // 子类可扩展点
// 设置代理是否冻结(不允许后续修改)
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true); // 告知代理工厂,拦截器已预过滤
}
// 获取合适的类加载器
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader smartClassLoader &&
classLoader != beanClass.getClassLoader()) {
classLoader = smartClassLoader.getOriginalClassLoader(); // 使用原始类加载器
}
// 根据 classOnly 决定是生成类还是实例
return (classOnly ? proxyFactory.getProxyClass(classLoader) : proxyFactory.getProxy(classLoader));
}
说明:
buildProxy(...)
是 Spring AOP 自动代理机制中的核心方法之一。它负责:
- 配置
ProxyFactory
; - 确定使用
JDK 动态代理
还是CGLIB 代理
,详见这篇; - 添加
Advisor
链和目标源(TargetSource); - 最终生成 代理类 或 代理实例。
方法流程:
-
暴露目标类信息
- 通过
AutoProxyUtils.exposeTargetClass(...)
将目标类信息暴露给 BeanFactory,便于后续调试/日志分析。
- 通过
-
初始化 ProxyFactory
- 创建一个新的
ProxyFactory
实例,并从当前自动代理创建器中复制配置(如 proxyTargetClass、exposeProxy 等)。
- 创建一个新的
-
判断代理方式(JDK vs CGLIB)
- 如果
proxyTargetClass == true
:强制使用 CGLIB。- 若目标类是动态代理类或 Lambda 表达式,则添加其所有实现的接口,以支持引入增强。
- 否则调用
shouldProxyTargetClass(...)
判断是否应使用 CGLIB。- 如果不是,则尝试通过
evaluateProxyInterfaces(...)
使用 JDK 动态代理。
- 如果不是,则尝试通过
- 如果
-
构建并添加 Advisor 链
- 通过
buildAdvisors(...)
方法将拦截器(Advice
)转换为Advisor
类型; - 将这些 Advisor 添加到
ProxyFactory
中。
- 通过
-
设置 TargetSource
- 将传入的
TargetSource
设置进ProxyFactory
。
- 将传入的
-
自定义 ProxyFactory
- 提供给子类扩展的方法
customizeProxyFactory(...)
,用于进一步配置代理工厂。
- 提供给子类扩展的方法
-
设置代理属性
- 设置代理是否“冻结”(不可再添加 Advice);
- 如果拦截器已经预先过滤过
advisorsPreFiltered()
,则跳过运行时检查。
-
选择类加载器
- 若当前类加载器为
SmartClassLoader
且与目标类不同,则使用原始类加载器,避免类冲突。
- 若当前类加载器为
-
生成代理
- 如果
classOnly == true
:仅生成代理类; - 否则:创建代理实例。
- 如果
关键方法:
方法 | 作用 |
---|---|
buildAdvisors(...) | 将拦截器封装为 Advisor ,供 AOP 使用 |
shouldProxyTargetClass(...) | 判断是否应该使用目标类进行代理(即是否启用 CGLIB) |
evaluateProxyInterfaces(...) | 分析目标类接口,决定是否使用 JDK 动态代理 |
customizeProxyFactory(...) | 子类可重写此方法来自定义代理工厂行为 |
getProxyClassLoader() | 获取用于生成代理类的类加载器 |
示例:
假设有一个 Service 类:
public class OrderService {
public void placeOrder() {
// ...
}
}
并为其配置了一个切面 LogAspect:
@Aspect
@Component
public class LogAspect {
@Before("execution(* OrderService.*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint);
}
}
Spring 容器在启动时会调用 buildProxy(...)
方法,最终生成一个包装了 OrderService
的代理对象,调用 placeOrder()
时会先执行 LogAspect.before(...)
,再执行目标方法。
小结:
buildProxy(...)
是 Spring AOP 自动代理创建的核心逻辑。buildProxy(...)
决定了代理方式(JDK / CGLIB)、构建拦截器链、设置目标源,并最终生成代理类或实例。- 支持灵活的扩展机制(如
customizeProxyFactory
,适合各种复杂场景下的 AOP 应用。
六、AbstractAdvisorAutoProxyCreator
1. 简介
- 核心功能 —— 根据匹配的通知器(
Advisor
)动态地为 Bean 创建 AOP 代理 - 继承
AbstractAutoProxyCreator
- 3个
AutoProxyCreator
都继承AbstractAdvisorAutoProxyCreator
2. getAdvicesAndAdvisorsForBean(...)
方法
/**
* 确定给定 Bean 是否需要被代理,并返回适用于该 Bean 的通知(Advice)和通知器(Advisor)。
*
* <p>此方法会查找所有可以应用到当前 Bean 的通知器(Advisor),如果找到至少一个,
* 则返回这些通知器数组,表示需要为该 Bean 创建代理;
* 如果没有找到任何通知器,则返回 DO_NOT_PROXY,表示不进行代理。
*
* @param beanClass 当前要代理的目标 Bean 的类对象
* @param beanName 当前要代理的目标 Bean 的名称
* @param targetSource 自定义的目标源(TargetSource),可能为 null
* @return 返回适用于该 Bean 的拦截器或通知器数组,若不需要代理则返回 DO_NOT_PROXY
* @throws BeansException 如果在处理过程中发生异常
*/
protected Object @Nullable [] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 查找适用于当前 Bean 的所有符合条件的通知器
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
// 如果没有符合条件的通知器,则返回 DO_NOT_PROXY 表示不创建代理
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
// 否则将通知器列表转为数组返回,表示需要创建代理并应用这些通知器
return advisors.toArray();
}
说明:
- 功能:判断指定 Bean 是否需要被 AOP 代理,并获取相关的通知器。
- 逻辑流程:
- 调用
findEligibleAdvisors
方法查找所有适用于该 Bean 的通知器。 - 如果没有找到通知器,则返回
DO_NOT_PROXY
,即不创建代理。 - 如果有通知器,则将其转换为数组返回,Spring 会根据这些通知器为 Bean 创建代理对象。
- 调用
使用场景:
该方法是 AOP 自动代理机制的核心方法之一,由 Spring 容器在 Bean 生命周期中调用,用于决定是否对某个 Bean 进行增强(AOP 代理)。
3. findEligibleAdvisors(...)
方法
/**
* 查找所有适用于当前类的、可以用于自动代理的通知器(Advisor)。
*
* <p>该方法会完成以下步骤:
* 1. 获取所有的候选通知器(通过 {@link #findCandidateAdvisors()})。
* 2. 过滤出能够应用到当前 Bean 的通知器(通过 {@link #findAdvisorsThatCanApply(List, Class, String)})。
* 3. 扩展通知器列表(通过 {@link #extendAdvisors(List)}),允许子类添加额外的通知器。
* 4. 如果有可用的通知器,则根据顺序进行排序(通过 {@link #sortAdvisors(List)})。
*
* @param beanClass 当前需要查找通知器的目标 Bean 的类对象
* @param beanName 当前正在被代理的 Bean 的名称
* @return 返回符合条件的通知器列表。如果没有任何通知器适用,返回空列表(不会返回 null)
*
* @see #findCandidateAdvisors()
* @see #sortAdvisors(List)
* @see #extendAdvisors(List)
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 1. 获取所有候选的通知器(通常是 Spring 容器中所有类型为 Advisor 的 Bean)
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 2. 过滤出适用于当前 Bean 的通知器(基于切点匹配)
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 3. 允许子类扩展,添加一些自定义的通知器(例如上下文相关的通知器)
extendAdvisors(eligibleAdvisors);
// 4. 如果有通知器,按顺序排序(支持 @Order 注解或 Ordered 接口)
if (!eligibleAdvisors.isEmpty()) {
try {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
catch (BeanCreationException ex) {
throw new AopConfigException("通知器排序失败,可能是由于自定义实现了 Ordered 接口导致的 Bean 创建问题。" +
"建议改用 @Order 注解进行排序。", ex);
}
}
// 返回最终筛选并排序后的通知器列表
return eligibleAdvisors;
}
说明:
- 功能:此方法是
AbstractAdvisorAutoProxyCreator
中的核心逻辑之一,负责查找、过滤、扩展和排序适用于某个 Bean 的通知器(Advisor)。 - 主要流程:
- 获取候选通知器:通常是从 Spring 容器中获取所有类型为
Advisor
的 Bean。 - 筛选适用的通知器:使用 AOP 工具类判断哪些通知器可以应用到目标 Bean 上(基于
Pointcut
或者Introduction
匹配)。 - 扩展通知器列表:提供一个钩子方法供子类实现,可动态添加额外的通知器。
- 排序通知器:对匹配的通知器按照优先级进行排序,确保拦截顺序可控。
- 获取候选通知器:通常是从 Spring 容器中获取所有类型为
- 异常处理:在排序过程中若出现 Bean 创建异常,会封装成 AopConfigException 抛出,并提示建议使用
@Order
注解代替Ordered
接口。
使用场景:
该方法由getAdvicesAndAdvisorsForBean()
调用,用于决定是否为某个 Bean 创建代理以及为其添加哪些增强逻辑(Advice)。
4. findEligibleAdvisors(...)
方法
/**
* 查找所有可用于自动代理的候选通知器(Advisor)。
*
* <p>该方法通常用于获取 Spring 容器中所有的 Advisor 类型 Bean,
* 供后续筛选哪些通知器可以应用到目标 Bean 上。
*
* @return 返回一个包含所有候选通知器(Advisor)的列表
* @throws IllegalStateException 如果当前未初始化 advisorRetrievalHelper,抛出异常
*/
protected List<Advisor> findCandidateAdvisors() {
// 确保 advisorRetrievalHelper 已经初始化
Assert.state(this.advisorRetrievalHelper != null,
"没有可用的 BeanFactoryAdvisorRetrievalHelper,请确认是否已完成初始化");
// 委托给 advisorRetrievalHelper 来查找容器中所有类型为 Advisor 的 Bean
return this.advisorRetrievalHelper.findAdvisorBeans();
}
说明:
- 功能:此方法负责从 Spring 容器中获取所有类型为
Advisor
的 Bean,作为候选的通知器,用于后续判断哪些可以应用到当前 Bean 上。 - 子类可以重写:
AnnotationAwareAspectJAutoProxyCreator
重写此方法用来支持@Aspect
。 - 实现细节:
- 使用了
advisorRetrievalHelper
来实际完成查找工作。 - 通过
Assert.state(...)
确保advisorRetrievalHelper
已被正确初始化。
- 使用了
使用场景:
该方法被findEligibleAdvisors()
调用,是 AOP 自动代理流程的第一步,即获取所有可能的通知器。
5. findAdvisorsThatCanApply(...)
方法
/**
* 在给定的候选通知器(Advisor)中,查找所有可以应用到指定 Bean 的通知器。
*
* <p>该方法会使用 AOP 工具类 {@link AopUtils#findAdvisorsThatCanApply(List, Class)} 来判断
* 每个 Advisor 是否匹配目标 Bean 的类或方法,从而决定是否将其加入最终的增强逻辑中。
*
* @param candidateAdvisors 候选的通知器列表(通常是从 Spring 容器中获取的所有 Advisor)
* @param beanClass 目标 Bean 的类对象
* @param beanName 当前正在被代理的 Bean 的名称
* @return 返回可以应用到该 Bean 的通知器列表
*
* @see ProxyCreationContext#getCurrentProxiedBeanName()
*/
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
// 设置当前正在代理的 Bean 名称,供后续处理(如日志、调试等)使用
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 使用 AopUtils 工具类筛选出能够应用到当前 Bean 的通知器
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
// 清除当前线程中保存的代理 Bean 名称,避免影响其他 Bean 的处理
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
说明:
- 功能:从候选通知器中筛选出适用于当前 Bean 的通知器(
Advisor
),即根据Pointcut
或者Introduction
匹配目标 Bean。 - 实现细节:
- 使用
AopUtils.findAdvisorsThatCanApply(...)
进行实际的匹配判断。 - 利用
ProxyCreationContext
设置和清理当前正在代理的 Bean 名称,便于上下文追踪。
- 使用
- 使用场景:该方法在
findEligibleAdvisors()
中被调用,用于过滤出真正适用于某个 Bean 的增强逻辑。
关键工具类:
AopUtils.findAdvisorsThatCanApply()
:核心匹配逻辑,基于Advisor
的Pointcut
或者Introduction
匹配目标类或方法。
七、Advisor
PointcutAdvisor
和 IntroductionAdvisor
是 Spring AOP 中两种不同类型的 通知器(Advisor),它们分别用于不同的增强场景。
✅ 1. 核心功能对比
对比维度 | PointcutAdvisor | IntroductionAdvisor |
---|---|---|
作用 | 定义在特定切点(Pointcut)上执行的通知(Advice),用于拦截方法调用并进行增强(如日志、事务等)。 | 用于为目标类引入新的接口和实现(即 mixin),使目标对象具有额外的功能或接口行为。 |
匹配粒度 | 支持 类 + 方法级别 的匹配,通过Pointcut 判断是否对某个方法进行拦截。 | 只支持 类级别 的匹配,不涉及方法级别的判断。 |
是否包含切点 | ✅ 包含切点(Pointcut) | ❌ 不直接包含切点,但可通过ClassFilter 进行类级别的过滤。 |
是否可以引入新接口 | ❌ 不能引入新的接口或行为 | ✅ 可以为目标类动态添加接口及其实现 |
✅ 2. 接口定义对比
1. PointcutAdvisor
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
- 功能:提供一个切点
Pointcut
,用于决定哪些类/方法需要被增强。 - 应用场景:
- 日志记录
- 权限控制
- 事务管理
- 典型实现:
DefaultPointcutAdvisor
AspectJExpressionPointcutAdvisor
2. IntroductionAdvisor
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
ClassFilter getClassFilter();
void validateInterfaces() throws IllegalArgumentException;
}
- 功能:
- 提供一个类过滤器
ClassFilter
,用于判断该引入通知是否适用于目标类。 - 提供要引入的接口列表(通过
IntroductionInfo
接口)。 - 验证这些接口是否可以正确引入到目标类上。
- 提供一个类过滤器
- 应用场景:
- 给目标类动态添加接口和实现(例如监控接口、mixin)
- 实现“透明”增强,比如
IsModified
接口跟踪对象是否修改过
- 典型实现:
DefaultIntroductionAdvisor
✅ 3. 使用示例
示例 1:PointcutAdvisor —— 拦截方法调用
PointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
return clazz.getName().contains("Service");
}
});
advisor.setAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Method is about to be called: " + method.getName());
}
});
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logMethodCall(JoinPoint jp) {
System.out.println("Calling method: " + jp.getSignature().getName());
}
}
示例 2:IntroductionAdvisor —— 引入接口
public interface Monitorable {
boolean isModified();
}
public class ModifiedStateIntroductionInterceptor implements MethodInterceptor, IntroductionInfo {
private boolean modified = false;
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (isModificationMethod(mi.getMethod())) {
modified = true;
}
return mi.proceed();
}
// IntroductionInfo 接口方法
@Override
public Class<?>[] getInterfaces() {
return new Class<?>[] { Monitorable.class };
}
public boolean isModified() {
return modified;
}
}
// 创建 IntroductionAdvisor
IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(
new ModifiedStateIntroductionInterceptor(), Monitorable.class);
✅ 4. Spring 内部处理逻辑区别
在 Spring AOP 处理过程中,PointcutAdvisor
和 IntroductionAdvisor
会被分别处理:
处理阶段 | PointcutAdvisor | IntroductionAdvisor |
---|---|---|
匹配方式 | 使用 canApply(PointcutAdvisor.getPointcut(), clazz) 进行类+方法匹配 | 使用 getClassFilter().matches(clazz) 进行类级别匹配 |
优先级 | 在处理完 IntroductionAdvisor 后再处理 | 优先处理,因为影响代理类型生成(如是否实现新接口) |
是否影响代理类型 | ❌ 通常不影响 | ✅ 影响,若引入了接口,则代理必须实现该接口 |
✅ 5. 总结对比
特性 | PointcutAdvisor | IntroductionAdvisor |
---|---|---|
是否包含切点 | ✅ 是 | ❌ 否 |
匹配粒度 | 方法级别 | 类级别 |
是否可引入新接口 | ❌ 否 | ✅ 是 |
典型用途 | 方法拦截、增强 | 添加接口与行为 |
接口方法 | getPointcut() | getClassFilter() , validateInterfaces() , getInterfaces() |
实现接口 | Advisor | Advisor , IntroductionInfo |
常见实现类 | DefaultPointcutAdvisor | DefaultIntroductionAdvisor |
是否影响代理类型 | ❌ 否 | ✅ 是 |
✅ 结论
- 如果需要 拦截某些方法并执行增强操作(如日志、权限校验),请选择
PointcutAdvisor
。 - 如果希望 为目标类增加新的接口行为(如监控、状态追踪),请选择
IntroductionAdvisor
。