EnableAspectJAutoProxy优化

master
linlei 2024-05-06 17:59:52 +08:00
parent 7164746998
commit 99249afe35
21 changed files with 325 additions and 214 deletions

View File

@ -217,16 +217,21 @@
- [AdvisorAdapterRegistry](spring-aop/spring-aop-advisorAdapterRegistry/README.md)适配各种Advice到AOP拦截器注册和管理Advisor适配器。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [AdvisorAdapter](spring-aop/spring-aop-advisorAdapter/README.md):适配不同类型通知到拦截器链。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [ProxyMethodInvocation](spring-aop/spring-aop-proxyMethodInvocation/README.md)AOP方法调用代理处理拦截器链和方法调用。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [@EnableAspectJAutoProxy](spring-aop/spring-aop-enableAspectJAutoProxy/README.md)
启用AspectJ切面自动代理。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [AnnotationAwareAspectJAutoProxyCreator](spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/README.md)
创建AOP代理以应用AspectJ风格的切面。<img src="https://img.shields.io/badge/Level-%E5%9B%B0%E9%9A%BE-%23FF3030"></img>
- [BeanFactoryAspectJAdvisorsBuilder](spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/README.md)
:构建@AspectJ注解切面生成Spring AOP
Advisors。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [BeanFactoryAdvisorRetrievalHelper](spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/README.md):帮助检索并管理
Spring AOP 中的 Advisor Beans。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [TargetSource](spring-aop/spring-aop-targetSource/README.md)管理AOP代理对象的获取与释放。<img src="https://img.shields.io/badge/Level-%E7%AE%80%E5%8D%95-0099ff"></img>
- [TargetSourceCreator](spring-aop/spring-aop-targetSourceCreator/README.md):创建特殊的目标源,定制代理对象的创建和管理。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [@EnableAspectJAutoProxy](spring-aop/spring-aop-enableAspectJAutoProxy/README.md)启用AspectJ切面自动代理。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [@EnableLoadTimeWeaving](spring-aop/spring-aop-enableLoadTimeWeaving/README.md)启用Spring加载时编织。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [AspectInstanceFactory](spring-aop/spring-aop-aspectInstanceFactory/README.md):创建切面实例,支持多种实现方式。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [MetadataAwareAspectInstanceFactory](spring-aop/spring-aop-metadataAwareAspectInstanceFactory/README.md):管理切面实例和元数据,支持多种实例化策略。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [AspectJAdvisorFactory](spring-aop/spring-aop-aspectJAdvisorFactory/README.md)创建AspectJ通知器实例管理切面通知的创建和配置。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [BeanFactoryAspectJAdvisorsBuilder](spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/README.md):构建@AspectJ注解切面生成Spring AOP Advisors。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [BeanFactoryAdvisorRetrievalHelper](spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/README.md):帮助检索并管理 Spring AOP 中的 Advisor Beans。<img src="https://img.shields.io/badge/Level-%E4%B8%80%E8%88%AC-%23FF6347"></img>
- [AnnotationAwareAspectJAutoProxyCreator](spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/README.md)创建AOP代理以应用AspectJ风格的切面。<img src="https://img.shields.io/badge/Level-%E5%9B%B0%E9%9A%BE-%23FF3030"></img>
- [AopContext](spring-aop/spring-aop-aopContext/README.md)获取Spring AOP代理对象的工具。<img src="https://img.shields.io/badge/Level-%E7%AE%80%E5%8D%95-0099ff"></img>
- [ExposeInvocationInterceptor](spring-aop/spring-aop-exposeInvocationInterceptor/README.md)暴露Spring AOP方法调用上下文的拦截器。<img src="https://img.shields.io/badge/Level-%E7%AE%80%E5%8D%95-0099ff"></img>

View File

@ -1,4 +1,5 @@
## AnnotationAwareAspectJAutoProxyCreator
- [AnnotationAwareAspectJAutoProxyCreator](#annotationawareaspectjautoproxycreator)
- [一、基本信息](#一基本信息)
- [二、基本描述](#二基本描述)
@ -7,7 +8,6 @@
- [五、最佳实践](#五最佳实践)
- [六、时序图](#六时序图)
- [七、源码分析](#七源码分析)
- [八、常见问题](#八常见问题)
### 一、基本信息
@ -71,17 +71,9 @@ class BeanPostProcessor {
class InstantiationAwareBeanPostProcessor {
<<Interface>>
}
class Ordered {
<<Interface>>
}
class ProxyConfig
class ProxyProcessorSupport
class Serializable {
<<Interface>>
}
class SmartInstantiationAwareBeanPostProcessor {
<<Interface>>
@ -96,45 +88,81 @@ AspectJAwareAdvisorAutoProxyCreator --> AbstractAdvisorAutoProxyCreator
BeanClassLoaderAware --> Aware
BeanFactoryAware --> Aware
InstantiationAwareBeanPostProcessor --> BeanPostProcessor
ProxyConfig ..> Serializable
ProxyProcessorSupport ..> AopInfrastructureBean
ProxyProcessorSupport ..> BeanClassLoaderAware
ProxyProcessorSupport ..> Ordered
ProxyProcessorSupport --> ProxyConfig
SmartInstantiationAwareBeanPostProcessor --> InstantiationAwareBeanPostProcessor
~~~
### 五、最佳实践
`AnnotationAwareAspectJAutoProxyCreator`类以及注解驱动的切面编程。通过注册`AnnotationAwareAspectJAutoProxyCreator`作为Bean并指定应用程序配置类Spring容器能够自动创建切面代理并在运行时织入切面逻辑。最后从容器中获取`MyService` bean并调用其方法实现了面向切面编程的横切关注点的功能。
使用`EnableAspectJAutoProxy`
注解和Spring的基于注解的应用上下文来启用AspectJ自动代理功能。在程序中首先创建了一个基于注解的应用上下文然后通过该上下文获取了`MyService`
bean并调用了其方法。
```java
public class AnnotationAwareAspectJAutoProxyCreatorDemo {
public class EnableAspectJAutoProxyDemo {
public static void main(String[] args) {
// 创建一个默认的 Bean 工厂
AnnotationConfigApplicationContext beanFactory = new AnnotationConfigApplicationContext();
// 注册AnnotationAwareAspectJAutoProxyCreator作为Bean用于自动创建切面代理
beanFactory.registerBeanDefinition("internalAutoProxyCreator", new RootBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class));
// 注册应用程序配置类
beanFactory.register(AppConfig.class);
// 刷新应用程序上下文
beanFactory.refresh();
// 从容器中获取MyService bean
MyService myService = beanFactory.getBean(MyService.class);
// 创建基于注解的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从应用上下文中获取MyService bean
MyService myService = context.getBean(MyService.class);
// 调用MyService的方法
myService.doSomething();
myService.foo();
}
}
```
运行结果,执行`MyService`中的`doSomething()`方法之前和之后,切面逻辑已成功织入。
`AppConfig` 类是一个使用 `@Configuration` 注解标记的配置类,通过 `@EnableAspectJAutoProxy` 开启了 AspectJ
自动代理功能,并通过 `@ComponentScan` 启用了组件扫描,用于自动发现和注册 Spring 组件。
```java
Before executing the method...
Doing something...
After executing the method...
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
}
```
`MyService` 类是一个使用 `@Service` 注解标记的服务类,提供了一个名为 `foo()` 的方法,该方法在调用时会打印消息 "foo..."。
```java
@Service
public class MyService {
public void foo() {
System.out.println("foo...");
}
}
```
`MyAspect`是一个使用了`@Aspect`注解的Java类表示它是一个切面。在这个类中定义了一个名为`advice`的方法,并使用了`@Before`
注解来指定在目标方法执行之前执行的通知。
```java
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.xcs.spring.MyService+.*(..))")
public void before() {
System.out.println("Before method execution");
}
}
```
运行结果,调用 `MyService` 类的 `foo()` 方法之前,成功地执行了一个切面通知,输出了 "Before method execution"
的消息,然后执行了 `foo()` 方法,输出了 "foo..." 的消息。
```java
Before method
execution
foo...
```
### 六、时序图
@ -569,18 +597,3 @@ protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
return proxyFactory.getProxy(classLoader);
}
```
### 八、常见问题
1. **无法注入依赖**
+ 可能会遇到无法注入依赖的问题这通常是由于AOP代理的顺序问题导致的。
2. **切面未生效**
+ 有时配置了切面但是切面并没有生效可能是由于切面表达式不正确或者AOP代理配置错误导致的。
4. **Bean未被代理**
+ 有时候配置了AnnotationAwareAspectJAutoProxyCreator但是某些Bean并没有被代理可能是由于Bean的作用域、类型或其他条件不满足自动代理的条件。

View File

@ -1,24 +1,15 @@
package com.xcs.spring;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AnnotationAwareAspectJAutoProxyCreatorDemo {
public static void main(String[] args) {
// 创建一个默认的 Bean 工厂
AnnotationConfigApplicationContext beanFactory = new AnnotationConfigApplicationContext();
// 注册AnnotationAwareAspectJAutoProxyCreator作为Bean用于自动创建切面代理
beanFactory.registerBeanDefinition("internalAutoProxyCreator", new RootBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class));
// 注册应用程序配置类
beanFactory.register(AppConfig.class);
// 刷新应用程序上下文
beanFactory.refresh();
// 从容器中获取MyService bean
MyService myService = beanFactory.getBean(MyService.class);
// 创建基于注解的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从应用上下文中获取MyService bean
MyService myService = context.getBean(MyService.class);
// 调用MyService的方法
myService.doSomething();
myService.foo();
}
}

View File

@ -2,8 +2,11 @@ package com.xcs.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.xcs.spring")
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
}

View File

@ -1,21 +1,15 @@
package com.xcs.spring;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
class MyAspect {
public class MyAspect {
@Before("execution(* com.xcs.spring.MyService.doSomething(..))")
@Before("execution(* com.xcs.spring.MyService+.*(..))")
public void before() {
System.out.println("Before executing the method..." );
}
@After("execution(* com.xcs.spring.MyService.doSomething(..))")
public void after() {
System.out.println("After executing the method..." );
System.out.println("Before method execution");
}
}

View File

@ -4,7 +4,8 @@ import org.springframework.stereotype.Service;
@Service
public class MyService {
public void doSomething() {
System.out.println("Doing something...");
public void foo() {
System.out.println("foo...");
}
}

View File

@ -5,8 +5,8 @@
- [二、基本描述](#二基本描述)
- [三、主要功能](#三主要功能)
- [四、最佳实践](#四最佳实践)
- [五、源码分析](#五源码分析)
- [六、常见问题](#六常见问题)
- [五、时序图](#五时序图)
- [六、源码分析](#六源码分析)
### 一、基本信息
@ -33,30 +33,44 @@
### 四、最佳实践
使用 `BeanFactoryAdvisorRetrievalHelper` 类来从一个默认的 Bean 工厂中检索 Advisor并打印出这些 Advisor 的列表。首先,我们创建一个默认的 Bean 工厂,并向其注册一个名为 "myAdvisor" 的 Advisor。然后我们创建了 `BeanFactoryAdvisorRetrievalHelper` 实例,并将 Bean 工厂传入其中。接着,通过调用 `findAdvisorBeans()` 方法,我们获取了 Bean 工厂中的 Advisor 列表,并通过循环遍历的方式打印出每个 Advisor 的信息。
使用基于注解的应用上下文来获取并调用 `MyService` Bean 的 `foo()`
方法。首先,创建了一个 `AnnotationConfigApplicationContext` 实例,通过传入 `AppConfig.class`
来初始化基于注解的应用上下文。然后,通过 `context.getBean(MyService.class)` 获取了 `MyService` Bean
的实例,并调用了其 `foo()` 方法。
```java
public class BeanFactoryAdvisorRetrievalHelperDemo {
public static void main(String[] args) {
// 创建一个默认的 Bean 工厂
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 向 Bean 工厂注册一个名为 "myAdvisor" 的 Advisor
beanFactory.registerSingleton("myAdvisor", new MyAdvisor());
// 创建 BeanFactoryAdvisorRetrievalHelper 实例,并传入 Bean 工厂
BeanFactoryAdvisorRetrievalHelper helper = new BeanFactoryAdvisorRetrievalHelper(beanFactory);
// 获取 Bean 工厂中的 Advisor 列表
List<Advisor> advisors = helper.findAdvisorBeans();
// 打印 Advisors
advisors.forEach(System.out::println);
// 创建基于注解的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从应用上下文中获取MyService bean
MyService myService = context.getBean(MyService.class);
// 调用MyService的方法
myService.foo();
}
}
```
`MyAdvisor` 类是一个自定义的 Advisor继承自 `AbstractPointcutAdvisor`,用于定义切面的逻辑。在该类中,`getPointcut()` 方法返回一个始终为真的 Pointcut表示适用于所有的连接点`getAdvice()` 方法返回一个空的 Advice表示不对目标方法添加任何额外的通知逻辑。因此该 Advisor 没有实际的业务逻辑,仅作为演示目的。
`AppConfig` 类是一个使用 `@Configuration` 注解标记的配置类,通过 `@EnableAspectJAutoProxy` 开启了 AspectJ
自动代理功能,并通过 `@ComponentScan` 启用了组件扫描,用于自动发现和注册 Spring 组件。
```java
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
}
```
使用 `@Component` 注解标记的自定义 Advisor继承自 `AbstractPointcutAdvisor`。它定义了一个总是返回真值的 Pointcut并将一个自定义的
Advice `MyAdvice` 应用于目标方法上。
```java
@Component
public class MyAdvisor extends AbstractPointcutAdvisor {
@Override
@ -66,18 +80,67 @@ public class MyAdvisor extends AbstractPointcutAdvisor {
@Override
public Advice getAdvice() {
return Advisor.EMPTY_ADVICE;
return new MyAdvice();
}
}
```
运行结果,成功地从 Bean 工厂中获取了Advisor。
`MyAdvice` 类是一个实现了 `MethodBeforeAdvice` 接口的自定义通知类,用于在目标方法执行前执行特定逻辑。在 `before()`
方法中,它打印了一条消息:"Before method execution"。
```java
com.xcs.spring.MyAdvisor@1f7030a6
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..."。
```java
@Service
public class MyService {
public void foo() {
System.out.println("foo...");
}
}
```
运行结果,调用 `MyService` 类的 `foo()` 方法之前,成功地执行了一个切面通知,输出了 "Before method execution"
的消息,然后执行了 `foo()` 方法,输出了 "foo..." 的消息。
```java
Before method
execution
foo...
```
### 五、时序图
~~~mermaid
sequenceDiagram
AbstractAutowireCapableBeanFactory->>AbstractAutoProxyCreator: postProcessAfterInitialization()
Note over AbstractAutowireCapableBeanFactory,AbstractAutoProxyCreator: 调用后处理方法
AbstractAutoProxyCreator->>AbstractAutoProxyCreator: wrapIfNecessary()
Note over AbstractAutoProxyCreator: 调用包装方法
AbstractAutoProxyCreator->>AbstractAdvisorAutoProxyCreator: getAdvicesAndAdvisorsForBean()
Note over AbstractAutoProxyCreator,AbstractAdvisorAutoProxyCreator: 获取通知和 Advisors
AbstractAdvisorAutoProxyCreator->>AbstractAdvisorAutoProxyCreator: findEligibleAdvisors()
Note over AbstractAdvisorAutoProxyCreator: 查找合适的 Advisors
AbstractAdvisorAutoProxyCreator->>AnnotationAwareAspectJAutoProxyCreator: findCandidateAdvisors()
Note over AbstractAdvisorAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator: 查找候选的 Advisors
AnnotationAwareAspectJAutoProxyCreator->>AbstractAdvisorAutoProxyCreator: super.findCandidateAdvisors()
Note over AnnotationAwareAspectJAutoProxyCreator,AbstractAdvisorAutoProxyCreator: 调用父类的查找候选的 Advisors
AbstractAdvisorAutoProxyCreator->>BeanFactoryAdvisorRetrievalHelper: findAdvisorBeans()
Note over AbstractAdvisorAutoProxyCreator,BeanFactoryAdvisorRetrievalHelper: 查找当前Bean工厂中所有符合条件的Advisor
BeanFactoryAdvisorRetrievalHelper->>AbstractAutoProxyCreator: 返回 advisors
~~~
### 六、源码分析
在`org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans`方法中,主要功能是在当前的 Bean 工厂中查找所有符合条件的 Advisor Beans。它忽略了 FactoryBeans并排除了当前正在创建中的 Beans。该方法首先确定 Advisor Bean 的名称列表,如果尚未缓存,则通过 `BeanFactoryUtils.beanNamesForTypeIncludingAncestors()` 方法获取。然后,它遍历这些 Advisor Bean 的名称,检查它们是否符合条件,并将符合条件的 Advisor Bean 添加到结果列表中。在添加之前,它会检查该 Bean 是否当前正在创建中,如果是,则跳过。最后,返回包含所有符合条件的 Advisor Beans 的列表。
@ -142,21 +205,3 @@ public List<Advisor> findAdvisorBeans() {
return advisors;
}
```
### 六、常见问题
1. **忽略FactoryBeans**
+ 在 `findAdvisorBeans()` 方法中,该类会忽略 FactoryBeans只处理常规的 Advisor Beans。这是因为 FactoryBeans 可能会在初始化时产生副作用,而 `BeanFactoryAdvisorRetrievalHelper` 需要保持所有常规 Beans 未初始化,以便自动代理创建器能够正确地应用于它们。
2. **排除当前正在创建的Beans**
+ 在遍历 Advisor Beans 名称列表时,`findAdvisorBeans()` 方法会排除当前正在创建中的 Beans。这是为了避免在 Bean 的创建过程中引入不稳定的代理逻辑。
3. **错误处理**
+ 当尝试获取 Advisor Bean 时,可能会抛出 `BeanCreationException` 异常。`BeanFactoryAdvisorRetrievalHelper` 需要正确处理这些异常情况,例如,当 Advisor Bean 的依赖 Bean 正在创建中时,可以选择跳过该 Advisor。
4. **缓存机制**
+ 为了提高性能,`BeanFactoryAdvisorRetrievalHelper` 类使用了缓存机制来存储 Advisor Bean 的名称列表。需要注意,在 Bean 工厂中添加或删除 Advisor Bean 时,需要更新缓存以确保数据的一致性。

View File

@ -0,0 +1,12 @@
package com.xcs.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
}

View File

@ -1,24 +1,15 @@
package com.xcs.spring;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import java.util.List;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class BeanFactoryAdvisorRetrievalHelperDemo {
public static void main(String[] args) {
// 创建一个默认的 Bean 工厂
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 向 Bean 工厂注册一个名为 "myAspect" 的 Advisor
beanFactory.registerSingleton("myAspect", new MyAdvisor());
// 创建 BeanFactoryAdvisorRetrievalHelper 实例,并传入 Bean 工厂
BeanFactoryAdvisorRetrievalHelper helper = new BeanFactoryAdvisorRetrievalHelper(beanFactory);
// 获取 Bean 工厂中的 Advisor 列表
List<Advisor> advisors = helper.findAdvisorBeans();
// 打印 Advisors
advisors.forEach(System.out::println);
// 创建基于注解的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从应用上下文中获取MyService bean
MyService myService = context.getBean(MyService.class);
// 调用MyService的方法
myService.foo();
}
}

View File

@ -0,0 +1,12 @@
package com.xcs.spring;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Before method execution");
}
}

View File

@ -1,10 +1,11 @@
package com.xcs.spring;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.stereotype.Component;
@Component
public class MyAdvisor extends AbstractPointcutAdvisor {
@Override
@ -14,6 +15,6 @@ public class MyAdvisor extends AbstractPointcutAdvisor {
@Override
public Advice getAdvice() {
return Advisor.EMPTY_ADVICE;
return new MyAdvice();
}
}

View File

@ -0,0 +1,11 @@
package com.xcs.spring;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void foo() {
System.out.println("foo...");
}
}

View File

@ -5,8 +5,8 @@
- [二、基本描述](#二基本描述)
- [三、主要功能](#三主要功能)
- [四、最佳实践](#四最佳实践)
- [五、源码分析](#五源码分析)
- [六、常见问题](#六常见问题)
- [五、时序图](#五时序图)
- [六、源码分析](#六源码分析)
### 一、基本信息
@ -36,63 +36,95 @@
### 四、最佳实践
使用 `BeanFactoryAspectJAdvisorsBuilder` 类来构建基于 AspectJ 注解的切面,首先创建了一个默认的 Bean 工厂,并注册了一个名为 "myAspect" 的单例 Bean然后通过 `BeanFactoryAspectJAdvisorsBuilder` 实例构建了 AspectJ Advisors并将其打印出来。
使用基于注解的应用上下文来获取并调用 `MyService` Bean 的 `foo()`
方法。首先,创建了一个 `AnnotationConfigApplicationContext` 实例,通过传入 `AppConfig.class`
来初始化基于注解的应用上下文。然后,通过 `context.getBean(MyService.class)` 获取了 `MyService` Bean
的实例,并调用了其 `foo()` 方法。
```java
public class BeanFactoryAspectJAdvisorsBuilderDemo {
public static void main(String[] args) {
// 创建一个默认的 Bean 工厂
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 在 Bean 工厂中注册一个名为 "myAspect" 的单例 Bean类型为 MyAspect
beanFactory.registerSingleton("myAspect", new MyAspect());
// 创建 BeanFactoryAspectJAdvisorsBuilder 实例,并传入 Bean 工厂和 ReflectiveAspectJAdvisorFactory 实例
BeanFactoryAspectJAdvisorsBuilder builder = new BeanFactoryAspectJAdvisorsBuilder(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory));
// 构建 AspectJ Advisors
List<Advisor> advisors = builder.buildAspectJAdvisors();
// 打印 Advisors
advisors.forEach(System.out::println);
// 创建基于注解的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从应用上下文中获取MyService bean
MyService myService = context.getBean(MyService.class);
// 调用MyService的方法
myService.foo();
}
}
```
使用了 AspectJ 的注解 `@Aspect` 进行标记。在该切面类中,包含了两个通知方法`before()` 和 `after()`,分别使用 `@Before``@After` 注解标记。这两个通知方法分别在目标方法 `com.xcs.spring.MyService.doSomething()` 执行之前和之后执行,并输出相应的日志信息。
`AppConfig` 类是一个使用 `@Configuration` 注解标记的配置类,通过 `@EnableAspectJAutoProxy` 开启了 AspectJ
自动代理功能,并通过 `@ComponentScan` 启用了组件扫描,用于自动发现和注册 Spring 组件。
```java
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
}
```
通过 @Aspect@Component 注解将其标记为 Spring 组件,并定义了一个在 com.xcs.spring.MyService 类的 foo
方法执行前执行的前置通知Before advice
```java
@Aspect
@Component
class MyAspect {
@Before("execution(* com.xcs.spring.MyService.doSomething(..))")
@Before("execution(* com.xcs.spring.MyService.foo(..))")
public void before() {
System.out.println("Before executing the method..." );
}
@After("execution(* com.xcs.spring.MyService.doSomething(..))")
public void after() {
System.out.println("After executing the method..." );
System.out.println("Before method execution");
}
}
```
定义了一个名为 `MyService` 的简单 Java 类,其中包含一个名为 `doSomething()` 的方法。该方法简单地打印一条日志信息 "Doing something..."。这个类作为示例类使用,用来演示在 AOP 中如何应用切面逻辑
`MyService` 类是一个使用 `@Service` 注解标记的服务类,提供了一个名为 `foo()` 的方法,该方法在调用时会打印消息 "foo..."。
```java
@Service
public class MyService {
public void doSomething() {
System.out.println("Doing something...");
public void foo() {
System.out.println("foo...");
}
}
```
运行结果,显示了两个 Advisor 对象的信息,它们分别对应着切面类 `MyAspect` 中的 `before()``after()` 方法,并针对相同的切点表达式 `execution(* com.xcs.spring.MyService.doSomething(..))`
运行结果,调用 `MyService` 类的 `foo()` 方法之前,成功地执行了一个切面通知,输出了 "Before method execution"
的消息,然后执行了 `foo()` 方法,输出了 "foo..." 的消息。
```java
InstantiationModelAwarePointcutAdvisor: expression [execution(* com.xcs.spring.MyService.doSomething(..))]; advice method [public void com.xcs.spring.MyAspect.before()]; perClauseKind=SINGLETON
InstantiationModelAwarePointcutAdvisor: expression [execution(* com.xcs.spring.MyService.doSomething(..))]; advice method [public void com.xcs.spring.MyAspect.after()]; perClauseKind=SINGLETON
Before method
execution
foo...
```
### 五、源码分析
### 五、时序图
~~~mermaid
sequenceDiagram
AbstractAutowireCapableBeanFactory->>AbstractAutoProxyCreator: postProcessAfterInitialization()
Note over AbstractAutowireCapableBeanFactory,AbstractAutoProxyCreator: 调用后处理方法
AbstractAutoProxyCreator->>AbstractAutoProxyCreator: wrapIfNecessary()
Note over AbstractAutoProxyCreator: 调用包装方法
AbstractAutoProxyCreator->>AbstractAdvisorAutoProxyCreator: getAdvicesAndAdvisorsForBean()
Note over AbstractAutoProxyCreator,AbstractAdvisorAutoProxyCreator: 获取通知和 Advisors
AbstractAdvisorAutoProxyCreator->>AbstractAdvisorAutoProxyCreator: findEligibleAdvisors()
Note over AbstractAdvisorAutoProxyCreator: 查找合适的 Advisors
AbstractAdvisorAutoProxyCreator->>AnnotationAwareAspectJAutoProxyCreator: findCandidateAdvisors()
Note over AbstractAdvisorAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator: 查找候选的 Advisors
AnnotationAwareAspectJAutoProxyCreator->>BeanFactoryAspectJAdvisorsBuilder: buildAspectJAdvisors()
Note over AnnotationAwareAspectJAutoProxyCreator,BeanFactoryAspectJAdvisorsBuilder: 构建 AspectJ Advisors
BeanFactoryAspectJAdvisorsBuilder->>AbstractAutoProxyCreator: 返回 advisors
~~~
### 六、源码分析
在`org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors`方法中,主要负责在当前的 Bean 工厂中查找使用 AspectJ 注解标记的切面 Bean并将其转换为 Spring AOP Advisors 的列表。它遍历所有的 Bean 名称,识别切面 Bean并根据其实例化模型单例或多例创建对应的 AspectJ Advisors。在处理过程中还会缓存单例切面的 Advisors以提高性能。
@ -226,8 +258,5 @@ private boolean hasAspectAnnotation(Class<?> clazz) {
}
```
### 六、常见问题
1. **实例化模型匹配**
+ 在判断切面的实例化模型时,需要确保该模型与实际的 Bean 实例化策略相匹配。如果切面 Bean 被声明为单例模式,但实际上是多例的,或者反之,则可能会导致不一致或异常情况。

View File

@ -0,0 +1,12 @@
package com.xcs.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
}

View File

@ -1,25 +1,15 @@
package com.xcs.spring;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder;
import org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import java.util.List;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class BeanFactoryAspectJAdvisorsBuilderDemo {
public static void main(String[] args) {
// 创建一个默认的 Bean 工厂
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 在 Bean 工厂中注册一个名为 "myAspect" 的单例 Bean类型为 MyAspect
beanFactory.registerSingleton("myAspect", new MyAspect());
// 创建 BeanFactoryAspectJAdvisorsBuilder 实例,并传入 Bean 工厂和 ReflectiveAspectJAdvisorFactory 实例
BeanFactoryAspectJAdvisorsBuilder builder = new BeanFactoryAspectJAdvisorsBuilder(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory));
// 构建 AspectJ Advisors
List<Advisor> advisors = builder.buildAspectJAdvisors();
// 打印 Advisors
advisors.forEach(System.out::println);
// 创建基于注解的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从应用上下文中获取MyService bean
MyService myService = context.getBean(MyService.class);
// 调用MyService的方法
myService.foo();
}
}

View File

@ -1,19 +1,15 @@
package com.xcs.spring;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
class MyAspect {
@Before("execution(* com.xcs.spring.MyService.doSomething(..))")
@Before("execution(* com.xcs.spring.MyService.foo(..))")
public void before() {
System.out.println("Before executing the method..." );
}
@After("execution(* com.xcs.spring.MyService.doSomething(..))")
public void after() {
System.out.println("After executing the method..." );
System.out.println("Before method execution");
}
}

View File

@ -1,7 +1,10 @@
package com.xcs.spring;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void doSomething() {
System.out.println("Doing something...");
public void foo() {
System.out.println("foo...");
}
}

View File

@ -1,13 +1,13 @@
## @EnableAspectJAutoProxy
- [@EnableAspectJAutoProxy](#@EnableAspectJAutoProxy)
- [@EnableAspectJAutoProxy](#enableaspectjautoproxy)
- [一、基本信息](#一基本信息)
- [二、基本描述](#二基本描述)
- [三、主要功能](#三主要功能)
- [四、注解源码](#注解源码)
- [四、注解源码](#注解源码)
- [五、最佳实践](#五最佳实践)
- [六、源码分析](#六源码分析)
- [七、常见问题](#七常见问题)
### 一、基本信息
@ -175,30 +175,23 @@ public class EnableAspectJAutoProxyDemo {
}
```
通过`@Configuration`注解表示它是一个配置类用于配置Spring应用的bean。其中通过`@EnableAspectJAutoProxy`
注解启用了AspectJ自动代理功能使得Spring能够自动处理切面。在配置中定义了两个bean`MyService`和`MyAspect`
,分别用于创建`MyService`的实例和`MyAspect`切面的实例。
`AppConfig` 类是一个使用 `@Configuration` 注解标记的配置类,通过 `@EnableAspectJAutoProxy` 开启了 AspectJ
自动代理功能,并通过 `@ComponentScan` 启用了组件扫描,用于自动发现和注册 Spring 组件。
```java
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyAspect myAspect() {
return new MyAspect();
}
}
```
`FooService`是一个简单的Java类其中包含了一个名为`foo`的方法
`MyService` 类是一个使用 `@Service` 注解标记的服务类,提供了一个名为 `foo()` 的方法,该方法在调用时会打印消息 "foo..."。
```java
@Service
public class MyService {
public void foo() {
@ -211,6 +204,7 @@ public class MyService {
```java
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.xcs.spring.MyService+.*(..))")
@ -220,6 +214,15 @@ public class MyAspect {
}
```
运行结果,调用 `MyService` 类的 `foo()` 方法之前,成功地执行了一个切面通知,输出了 "Before method execution"
的消息,然后执行了 `foo()` 方法,输出了 "foo..." 的消息。
```java
Before method
execution
foo...
```
### 六、源码分析
在`org.springframework.context.annotation.AspectJAutoProxyRegistrar#registerBeanDefinitions`方法中首先注册了AspectJ注解自动代理创建器然后获取了`@EnableAspectJAutoProxy`注解的属性。如果`@EnableAspectJAutoProxy`注解中指定了`proxyTargetClass`属性为true则强制使用CGLIB代理如果指定了`exposeProxy`属性为true则强制代理对象暴露为ThreadLocal。
@ -260,6 +263,8 @@ public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessar
在`org.springframework.aop.config.AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry,source)`方法中注册AspectJ注解自动代理创建器并且可以指定源对象。在方法中它调用了一个辅助方法`registerOrEscalateApcAsRequired`该方法会根据需要注册或升级AspectJ注解自动代理创建器并返回相应的BeanDefinition。
[AnnotationAwareAspectJAutoProxyCreator源码分析](../spring-aop-annotationAwareAspectJAutoProxyCreator/README.md)
```java
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(

View File

@ -1,20 +1,12 @@
package com.xcs.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyAspect myAspect() {
return new MyAspect();
}
}

View File

@ -2,8 +2,10 @@ package com.xcs.spring;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.xcs.spring.MyService+.*(..))")

View File

@ -1,5 +1,8 @@
package com.xcs.spring;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void foo() {