diff --git a/README.md b/README.md index 28757ba..5a13204 100644 --- a/README.md +++ b/README.md @@ -217,16 +217,21 @@ - [AdvisorAdapterRegistry](spring-aop/spring-aop-advisorAdapterRegistry/README.md):适配各种Advice到AOP拦截器,注册和管理Advisor适配器。 - [AdvisorAdapter](spring-aop/spring-aop-advisorAdapter/README.md):适配不同类型通知到拦截器链。 - [ProxyMethodInvocation](spring-aop/spring-aop-proxyMethodInvocation/README.md):AOP方法调用代理,处理拦截器链和方法调用。 + - [@EnableAspectJAutoProxy](spring-aop/spring-aop-enableAspectJAutoProxy/README.md) + :启用AspectJ切面自动代理。 + - [AnnotationAwareAspectJAutoProxyCreator](spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/README.md) + :创建AOP代理以应用AspectJ风格的切面。 + - [BeanFactoryAspectJAdvisorsBuilder](spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/README.md) + :构建@AspectJ注解切面,生成Spring AOP + Advisors。 + - [BeanFactoryAdvisorRetrievalHelper](spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/README.md):帮助检索并管理 + Spring AOP 中的 Advisor Beans。 - [TargetSource](spring-aop/spring-aop-targetSource/README.md):管理AOP代理对象的获取与释放。 - [TargetSourceCreator](spring-aop/spring-aop-targetSourceCreator/README.md):创建特殊的目标源,定制代理对象的创建和管理。 - - [@EnableAspectJAutoProxy](spring-aop/spring-aop-enableAspectJAutoProxy/README.md):启用AspectJ切面自动代理。 - [@EnableLoadTimeWeaving](spring-aop/spring-aop-enableLoadTimeWeaving/README.md):启用Spring加载时编织。 - [AspectInstanceFactory](spring-aop/spring-aop-aspectInstanceFactory/README.md):创建切面实例,支持多种实现方式。 - [MetadataAwareAspectInstanceFactory](spring-aop/spring-aop-metadataAwareAspectInstanceFactory/README.md):管理切面实例和元数据,支持多种实例化策略。 - [AspectJAdvisorFactory](spring-aop/spring-aop-aspectJAdvisorFactory/README.md):创建AspectJ通知器实例,管理切面通知的创建和配置。 - - [BeanFactoryAspectJAdvisorsBuilder](spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/README.md):构建@AspectJ注解切面,生成Spring AOP Advisors。 - - [BeanFactoryAdvisorRetrievalHelper](spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/README.md):帮助检索并管理 Spring AOP 中的 Advisor Beans。 - - [AnnotationAwareAspectJAutoProxyCreator](spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/README.md):创建AOP代理以应用AspectJ风格的切面。 - [AopContext](spring-aop/spring-aop-aopContext/README.md):获取Spring AOP代理对象的工具。 - [ExposeInvocationInterceptor](spring-aop/spring-aop-exposeInvocationInterceptor/README.md):暴露Spring AOP方法调用上下文的拦截器。 diff --git a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/README.md b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/README.md index 7b4f3f1..dcc4eba 100644 --- a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/README.md +++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/README.md @@ -1,4 +1,5 @@ ## AnnotationAwareAspectJAutoProxyCreator + - [AnnotationAwareAspectJAutoProxyCreator](#annotationawareaspectjautoproxycreator) - [一、基本信息](#一基本信息) - [二、基本描述](#二基本描述) @@ -7,7 +8,6 @@ - [五、最佳实践](#五最佳实践) - [六、时序图](#六时序图) - [七、源码分析](#七源码分析) - - [八、常见问题](#八常见问题) ### 一、基本信息 @@ -71,17 +71,9 @@ class BeanPostProcessor { class InstantiationAwareBeanPostProcessor { <> -} -class Ordered { -<> - } class ProxyConfig class ProxyProcessorSupport -class Serializable { -<> - -} class SmartInstantiationAwareBeanPostProcessor { <> @@ -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的作用域、类型或其他条件不满足自动代理的条件。 \ No newline at end of file diff --git a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AnnotationAwareAspectJAutoProxyCreatorDemo.java b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AnnotationAwareAspectJAutoProxyCreatorDemo.java index 2a5e3f3..2608580 100644 --- a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AnnotationAwareAspectJAutoProxyCreatorDemo.java +++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AnnotationAwareAspectJAutoProxyCreatorDemo.java @@ -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(); } } diff --git a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AppConfig.java b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AppConfig.java index b33612f..41e9108 100644 --- a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AppConfig.java +++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AppConfig.java @@ -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 { + } diff --git a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyAspect.java b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyAspect.java index 3baeade..fc285eb 100644 --- a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyAspect.java +++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyAspect.java @@ -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"); } } diff --git a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyService.java b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyService.java index 809682b..ea6a5c3 100644 --- a/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyService.java +++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyService.java @@ -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..."); } } diff --git a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/README.md b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/README.md index a887d9c..ad5a330 100644 --- a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/README.md +++ b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/README.md @@ -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 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 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 时,需要更新缓存以确保数据的一致性。 \ No newline at end of file diff --git a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/AppConfig.java b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/AppConfig.java new file mode 100644 index 0000000..41e9108 --- /dev/null +++ b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/AppConfig.java @@ -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 { + +} diff --git a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/BeanFactoryAdvisorRetrievalHelperDemo.java b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/BeanFactoryAdvisorRetrievalHelperDemo.java index 95ee8f5..fabb5df 100644 --- a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/BeanFactoryAdvisorRetrievalHelperDemo.java +++ b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/BeanFactoryAdvisorRetrievalHelperDemo.java @@ -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 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(); } } diff --git a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyAdvice.java b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyAdvice.java new file mode 100644 index 0000000..a206564 --- /dev/null +++ b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyAdvice.java @@ -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"); + } +} diff --git a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyAdvisor.java b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyAdvisor.java index df3aca9..55c7855 100644 --- a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyAdvisor.java +++ b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyAdvisor.java @@ -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(); } } diff --git a/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyService.java b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyService.java new file mode 100644 index 0000000..ea6a5c3 --- /dev/null +++ b/spring-aop/spring-aop-beanFactoryAdvisorRetrievalHelper/src/main/java/com/xcs/spring/MyService.java @@ -0,0 +1,11 @@ +package com.xcs.spring; + +import org.springframework.stereotype.Service; + +@Service +public class MyService { + + public void foo() { + System.out.println("foo..."); + } +} diff --git a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/README.md b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/README.md index 5dee7ab..09d6a00 100644 --- a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/README.md +++ b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/README.md @@ -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 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 被声明为单例模式,但实际上是多例的,或者反之,则可能会导致不一致或异常情况。 \ No newline at end of file diff --git a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/AppConfig.java b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/AppConfig.java new file mode 100644 index 0000000..41e9108 --- /dev/null +++ b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/AppConfig.java @@ -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 { + +} diff --git a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/BeanFactoryAspectJAdvisorsBuilderDemo.java b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/BeanFactoryAspectJAdvisorsBuilderDemo.java index c9cbe89..582eb65 100644 --- a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/BeanFactoryAspectJAdvisorsBuilderDemo.java +++ b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/BeanFactoryAspectJAdvisorsBuilderDemo.java @@ -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 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(); } } diff --git a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/MyAspect.java b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/MyAspect.java index 4c37fd5..18c136f 100644 --- a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/MyAspect.java +++ b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/MyAspect.java @@ -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"); } } diff --git a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/MyService.java b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/MyService.java index 843fa2c..8099049 100644 --- a/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/MyService.java +++ b/spring-aop/spring-aop-beanFactoryAspectJAdvisorsBuilder/src/main/java/com/xcs/spring/MyService.java @@ -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..."); } } diff --git a/spring-aop/spring-aop-enableAspectJAutoProxy/README.md b/spring-aop/spring-aop-enableAspectJAutoProxy/README.md index 99a2b26..d10d61d 100644 --- a/spring-aop/spring-aop-enableAspectJAutoProxy/README.md +++ b/spring-aop/spring-aop-enableAspectJAutoProxy/README.md @@ -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( diff --git a/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/AppConfig.java b/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/AppConfig.java index e8e9765..41e9108 100644 --- a/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/AppConfig.java +++ b/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/AppConfig.java @@ -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(); - } } diff --git a/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/MyAspect.java b/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/MyAspect.java index fd58ec4..fc285eb 100644 --- a/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/MyAspect.java +++ b/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/MyAspect.java @@ -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+.*(..))") diff --git a/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/MyService.java b/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/MyService.java index b4047e7..ea6a5c3 100644 --- a/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/MyService.java +++ b/spring-aop/spring-aop-enableAspectJAutoProxy/src/main/java/com/xcs/spring/MyService.java @@ -1,5 +1,8 @@ package com.xcs.spring; +import org.springframework.stereotype.Service; + +@Service public class MyService { public void foo() {