✒️ 作者 - Lex 📝 博客 - 掘金 📚 源码地址 - github
BeanFactoryAdvisorRetrievalHelper
类是 Spring AOP 框架中的辅助工具,用于在 Bean 工厂中检索 Advisor,这些 Advisor 定义了切面逻辑,可以在目标 Bean 的方法调用中织入相应的通知。
协助Advisor的检索
解析Advisor的Bean名称
适配不同类型的Advisor
辅助创建代理
使用基于注解的应用上下文来获取并调用 MyService
Bean 的 foo()
方法。首先,创建了一个 AnnotationConfigApplicationContext
实例,通过传入 AppConfig.class
来初始化基于注解的应用上下文。然后,通过 context.getBean(MyService.class)
获取了 MyService
Bean
的实例,并调用了其 foo()
方法。
public class BeanFactoryAdvisorRetrievalHelperDemo {
public static void main(String[] args) {
// 创建基于注解的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从应用上下文中获取MyService bean
MyService myService = context.getBean(MyService.class);
// 调用MyService的方法
myService.foo();
}
}
AppConfig
类是一个使用 @Configuration
注解标记的配置类,通过 @EnableAspectJAutoProxy
开启了 AspectJ
自动代理功能,并通过 @ComponentScan
启用了组件扫描,用于自动发现和注册 Spring 组件。
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
}
使用 @Component
注解标记的自定义 Advisor,继承自 AbstractPointcutAdvisor
。它定义了一个总是返回真值的 Pointcut,并将一个自定义的
Advice MyAdvice
应用于目标方法上。
@Component
public class MyAdvisor extends AbstractPointcutAdvisor {
@Override
public Pointcut getPointcut() {
return Pointcut.TRUE;
}
@Override
public Advice getAdvice() {
return new MyAdvice();
}
}
MyAdvice
类是一个实现了 MethodBeforeAdvice
接口的自定义通知类,用于在目标方法执行前执行特定逻辑。在 before()
方法中,它打印了一条消息:"Before method execution"。
public class MyAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Before method execution");
}
}
MyService
类是一个使用 @Service
注解标记的服务类,提供了一个名为 foo()
的方法,该方法在调用时会打印消息 "foo..."。
@Service
public class MyService {
public void foo() {
System.out.println("foo...");
}
}
运行结果,调用 MyService
类的 foo()
方法之前,成功地执行了一个切面通知,输出了 "Before method execution"
的消息,然后执行了 foo()
方法,输出了 "foo..." 的消息。
Before method
execution
foo...
在org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
方法中,主要功能是在当前的 Bean 工厂中查找所有符合条件的 Advisor Beans。它忽略了 FactoryBeans,并排除了当前正在创建中的 Beans。该方法首先确定 Advisor Bean 的名称列表,如果尚未缓存,则通过 BeanFactoryUtils.beanNamesForTypeIncludingAncestors()
方法获取。然后,它遍历这些 Advisor Bean 的名称,检查它们是否符合条件,并将符合条件的 Advisor Bean 添加到结果列表中。在添加之前,它会检查该 Bean 是否当前正在创建中,如果是,则跳过。最后,返回包含所有符合条件的 Advisor Beans 的列表。
/**
* 在当前 Bean 工厂中查找所有符合条件的 Advisor Bean,
* 忽略 FactoryBeans,并排除当前正在创建的 Bean。
* @return {@link org.springframework.aop.Advisor} Bean 的列表
* @see #isEligibleBean
*/
public List<Advisor> findAdvisorBeans() {
// 如果未缓存 Advisor Bean 的名称列表,则确定该列表。
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 不要在这里初始化 FactoryBeans我们需要保持所有常规 Bean 未初始化,以便自动代理创建器应用到它们上!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
// 遍历 Advisor Bean 名称列表
for (String name : advisorNames) {
// 检查 Bean 是否符合条件
if (isEligibleBean(name)) {
// 如果 Bean 当前正在创建中,则跳过
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 尝试获取 Advisor Bean,并添加到列表中
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
// 如果当前 Bean 依赖于正在创建的 Bean,则跳过
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// 忽略表示对当前正在尝试进行通知的 Bean 的引用。
// 我们希望找到除当前正在创建的 Bean 本身之外的其他 Advisor。
continue;
}
}
// 如果获取 Advisor Bean 失败,则抛出异常
throw ex;
}
}
}
}
return advisors;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。