eligibleAdvisors = new ArrayList<>();
+ // 遍历候选顾问列表
+ for (Advisor candidate : candidateAdvisors) {
+ // 如果候选顾问是引介顾问,并且可以应用于给定类,则将其添加到结果列表中
+ if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
+ eligibleAdvisors.add(candidate);
+ }
+ }
+ // 检查是否存在引介顾问
+ boolean hasIntroductions = !eligibleAdvisors.isEmpty();
+ // 继续遍历候选顾问列表
+ for (Advisor candidate : candidateAdvisors) {
+ // 如果候选顾问是引介顾问,则跳过
+ if (candidate instanceof IntroductionAdvisor) {
+ // 已经处理过
+ continue;
+ }
+ // 如果候选顾问可以应用于给定类,则将其添加到结果列表中
+ if (canApply(candidate, clazz, hasIntroductions)) {
+ eligibleAdvisors.add(candidate);
+ }
+ }
+ return eligibleAdvisors;
+}
+```
+
+在`org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class>, boolean)`方法中,判断给定的顾问是否能够在指定的类上应用。它首先检查顾问是否是引介顾问,如果是,则通过类过滤器来判断是否可以应用于目标类。如果顾问不是引介顾问,而是切点顾问,则通过切点来判断是否可以应用于目标类。如果顾问既不是引介顾问也不是切点顾问,则假设它适用于目标类。
+
+```java
+/**
+ * 判断给定的顾问是否能够在指定的类上应用。
+ * 这是一个重要的测试,因为它可以用于优化掉一个类的顾问。
+ * 这个版本还考虑了引介(对于IntroductionAwareMethodMatchers)。
+ * @param advisor 要检查的顾问
+ * @param targetClass 我们正在测试的类
+ * @param hasIntroductions 顾问链中是否包含任何引介
+ * @return 切点是否能够应用于任何方法
+ */
+public static boolean canApply(Advisor advisor, Class> targetClass, boolean hasIntroductions) {
+ // 如果顾问是引介顾问,则通过类过滤器来判断是否可以应用于目标类
+ if (advisor instanceof IntroductionAdvisor) {
+ return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
+ }
+ // 如果顾问是切点顾问,则通过切点来判断是否可以应用于目标类
+ else if (advisor instanceof PointcutAdvisor) {
+ PointcutAdvisor pca = (PointcutAdvisor) advisor;
+ return canApply(pca.getPointcut(), targetClass, hasIntroductions);
+ }
+ // 否则,假设它适用于目标类
+ else {
+ // 它没有切点,因此我们假设它适用。
+ return true;
+ }
+}
+```
+
+在`org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class>, boolean)`方法中,确定给定的切点是否能够在指定的类上应用。首先,它检查切点的类过滤器是否与目标类匹配。如果不匹配,则返回 false。如果类过滤器匹配目标类,它会检查方法匹配器是否为 MethodMatcher.TRUE,如果是,则表示切点适用于目标类的任何方法,直接返回 true。如果方法匹配器不是 MethodMatcher.TRUE,则遍历目标类及其所有接口,并检查每个类中的方法是否与切点匹配。如果找到匹配的方法,则返回 true;如果没有找到匹配的方法,则返回 false。
+
+```java
+/**
+ * 判断给定的切点是否能够在指定的类上应用。
+ *
这是一个重要的测试,因为它可以用于优化掉一个类的切点。
+ * @param pc 要检查的静态或动态切点
+ * @param targetClass 要测试的类
+ * @param hasIntroductions 顾问链中是否包含任何引介
+ * @return 切点是否能够应用于任何方法
+ */
+public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) {
+ Assert.notNull(pc, "切点不能为空");
+ // 首先检查类过滤器是否匹配目标类
+ if (!pc.getClassFilter().matches(targetClass)) {
+ return false;
+ }
+
+ MethodMatcher methodMatcher = pc.getMethodMatcher();
+ // 如果方法匹配器是 MethodMatcher.TRUE,则不需要遍历方法,直接返回true
+ if (methodMatcher == MethodMatcher.TRUE) {
+ // 如果我们匹配任何方法,则不需要遍历方法...
+ return true;
+ }
+
+ IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
+ if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
+ introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
+ }
+
+ // 获取目标类及其所有接口的集合
+ Set> classes = new LinkedHashSet<>();
+ // 如果目标类不是代理类,则将其添加到类集合中
+ if (!Proxy.isProxyClass(targetClass)) {
+ classes.add(ClassUtils.getUserClass(targetClass));
+ }
+ // 将目标类的所有接口添加到类集合中
+ classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
+
+ // 遍历类集合
+ for (Class> clazz : classes) {
+ // 获取类中声明的所有方法
+ Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
+ // 遍历方法
+ for (Method method : methods) {
+ // 如果存在引介感知的方法匹配器,并且方法匹配,则返回true;
+ // 否则,如果方法匹配器匹配方法,则返回true
+ if (introductionAwareMethodMatcher != null ?
+ introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
+ methodMatcher.matches(method, targetClass)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+```
+
+在`org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#extendAdvisors`方法中,将 `ExposeInvocationInterceptor` 添加到通知链的开头。这是必要的额外处理,特别是在使用 AspectJ 切点表达式和 AspectJ 风格的建议时。
+
+```java
+/**
+ * 将 {@link ExposeInvocationInterceptor} 添加到通知链的开头。
+ * 在使用AspectJ切点表达式和AspectJ风格的建议时,需要添加此额外的建议。
+ * @Override
+ * @param candidateAdvisors 候选的Advisors列表
+ */
+@Override
+protected void extendAdvisors(List candidateAdvisors) {
+ // 如果需要,使Advisor链支持AspectJ
+ AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
+}
+```
+
+在`org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy`方法中,首先检查`BeanFactory`是否是`ConfigurableListableBeanFactory`类型的,如果是,则调用`AutoProxyUtils.exposeTargetClass`方法来暴露目标类。然后创建一个`ProxyFactory`实例,并根据当前的代理配置进行设置。根据是否启用了代理目标类的标志,决定是否将代理目标类设置为true或false。接着构建适用于该bean的所有顾问,将它们添加到`ProxyFactory`中,并设置目标源为预先配置好的`TargetSource`。最后,根据当前的代理配置和代理类加载器,使用`ProxyFactory`获取代理实例并返回。
+
+```java
+/**
+ * 为给定的 bean 创建一个 AOP 代理。
+ * @param beanClass bean 的类
+ * @param beanName bean 的名称
+ * @param specificInterceptors 适用于此 bean 的拦截器集合(可能为空,但不为 null)
+ * @param targetSource 代理的 TargetSource,已预先配置以访问该 bean
+ * @return bean 的 AOP 代理
+ * @see #buildAdvisors
+ */
+protected Object createProxy(Class> beanClass, @Nullable String beanName,
+ @Nullable Object[] specificInterceptors, TargetSource targetSource) {
+
+ // 如果 beanFactory 是 ConfigurableListableBeanFactory 类型的,则暴露目标类
+ if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
+ AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
+ }
+
+ // 创建 ProxyFactory 实例
+ ProxyFactory proxyFactory = new ProxyFactory();
+ proxyFactory.copyFrom(this);
+
+ // 如果需要使用代理目标类,则设置为 true
+ if (proxyFactory.isProxyTargetClass()) {
+ // 对 JDK 代理目标进行显式处理(用于介绍建议场景)
+ if (Proxy.isProxyClass(beanClass)) {
+ // 必须允许引入;不能只设置接口为代理的接口。
+ for (Class> ifc : beanClass.getInterfaces()) {
+ proxyFactory.addInterface(ifc);
+ }
+ }
+ } else {
+ // 未强制代理目标类标志,让我们应用默认检查...
+ if (shouldProxyTargetClass(beanClass, beanName)) {
+ proxyFactory.setProxyTargetClass(true);
+ } else {
+ evaluateProxyInterfaces(beanClass, proxyFactory);
+ }
+ }
+
+ // 构建顾问数组
+ Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
+ // 将顾问添加到 ProxyFactory
+ proxyFactory.addAdvisors(advisors);
+ proxyFactory.setTargetSource(targetSource);
+ // 自定义 ProxyFactory
+ customizeProxyFactory(proxyFactory);
+
+ proxyFactory.setFrozen(this.freezeProxy);
+ if (advisorsPreFiltered()) {
+ proxyFactory.setPreFiltered(true);
+ }
+
+ // 如果 bean 类没有在重写类加载器中本地加载,则使用原始 ClassLoader
+ ClassLoader classLoader = getProxyClassLoader();
+ if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
+ classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
+ }
+ // 获取代理实例
+ 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
new file mode 100644
index 0000000..2a5e3f3
--- /dev/null
+++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AnnotationAwareAspectJAutoProxyCreatorDemo.java
@@ -0,0 +1,24 @@
+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);
+ // 调用MyService的方法
+ myService.doSomething();
+ }
+}
diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AppConfig.java b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AppConfig.java
similarity index 70%
rename from spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AppConfig.java
rename to spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AppConfig.java
index a8a3b1d..b33612f 100644
--- a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AppConfig.java
+++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/AppConfig.java
@@ -2,10 +2,8 @@ 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("com.xcs.spring")
public class AppConfig {
}
diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyAspect.java b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyAspect.java
similarity index 59%
rename from spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyAspect.java
rename to spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyAspect.java
index f2d8c7c..3baeade 100644
--- a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyAspect.java
+++ b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyAspect.java
@@ -1,5 +1,6 @@
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;
@@ -9,7 +10,12 @@ import org.springframework.stereotype.Component;
class MyAspect {
@Before("execution(* com.xcs.spring.MyService.doSomething(..))")
- public void beforeAdvice() {
+ 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..." );
+ }
}
diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyService.java b/spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyService.java
similarity index 100%
rename from spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyService.java
rename to spring-aop/spring-aop-annotationAwareAspectJAutoProxyCreator/src/main/java/com/xcs/spring/MyService.java
diff --git a/spring-aop/spring-aop-aspectj-after/pom.xml b/spring-aop/spring-aop-aspectj-after/pom.xml
deleted file mode 100644
index 81ab7b8..0000000
--- a/spring-aop/spring-aop-aspectj-after/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- com.xcs.spring
- spring-aop
- 0.0.1-SNAPSHOT
-
-
- 4.0.0
- spring-aop-aspectj-after
-
-
\ No newline at end of file
diff --git a/spring-aop/spring-aop-aspectj-afterReturning/pom.xml b/spring-aop/spring-aop-aspectj-afterReturning/pom.xml
deleted file mode 100644
index 41cabb8..0000000
--- a/spring-aop/spring-aop-aspectj-afterReturning/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- com.xcs.spring
- spring-aop
- 0.0.1-SNAPSHOT
-
-
- 4.0.0
- spring-aop-aspectj-afterReturning
-
-
\ No newline at end of file
diff --git a/spring-aop/spring-aop-aspectj-afterThrowing/pom.xml b/spring-aop/spring-aop-aspectj-afterThrowing/pom.xml
deleted file mode 100644
index 3da69cf..0000000
--- a/spring-aop/spring-aop-aspectj-afterThrowing/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- com.xcs.spring
- spring-aop
- 0.0.1-SNAPSHOT
-
-
- 4.0.0
- spring-aop-aspectj-afterThrowing
-
-
\ No newline at end of file
diff --git a/spring-aop/spring-aop-aspectj-around/pom.xml b/spring-aop/spring-aop-aspectj-around/pom.xml
deleted file mode 100644
index 9eb5db2..0000000
--- a/spring-aop/spring-aop-aspectj-around/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- com.xcs.spring
- spring-aop
- 0.0.1-SNAPSHOT
-
-
- 4.0.0
- spring-aop-aspectj-around
-
-
\ No newline at end of file
diff --git a/spring-aop/spring-aop-aspectj-aspect/README.md b/spring-aop/spring-aop-aspectj-aspect/README.md
deleted file mode 100644
index e6c562d..0000000
--- a/spring-aop/spring-aop-aspectj-aspect/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-## Aspect
-
-- [Aspect](#Aspect)
- - [一、基本信息](#一基本信息)
- - [二、基本描述](#二基本描述)
- - [三、主要功能](#三主要功能)
- - [四、接口源码](#四接口源码)
- - [五、主要实现](#五主要实现)
- - [六、最佳实践](#六最佳实践)
- - [七、源码分析](#七源码分析)
- - [八、常见问题](#八常见问题)
-
-### 一、基本信息
-
-✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading)
-
-### 二、基本描述
-
-
-
-### 三、主要功能
-
-### 四、接口源码
-
-### 五、主要实现
-
-### 六、最佳实践
-
-### 七、源码分析
-
-### 八、常见问题
\ No newline at end of file
diff --git a/spring-aop/spring-aop-aspectj-aspect/pom.xml b/spring-aop/spring-aop-aspectj-aspect/pom.xml
deleted file mode 100644
index e1e8bb5..0000000
--- a/spring-aop/spring-aop-aspectj-aspect/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- com.xcs.spring
- spring-aop
- 0.0.1-SNAPSHOT
-
-
- 4.0.0
- spring-aop-aspectj-aspect
-
-
\ No newline at end of file
diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AspectDemo.java b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AspectDemo.java
deleted file mode 100644
index b898878..0000000
--- a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/AspectDemo.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xcs.spring;
-
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-
-public class AspectDemo {
- public static void main(String[] args) {
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
- MyService service = context.getBean(MyService.class);
- System.out.println("MyService = " + service.getClass());
- service.doSomething();
-
- MyTestService myTestService = context.getBean(MyTestService.class);
- System.out.println("MyTestService = " + myTestService.getClass());
- myTestService.test();
- }
-}
diff --git a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyTestService.java b/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyTestService.java
deleted file mode 100644
index cf8a64f..0000000
--- a/spring-aop/spring-aop-aspectj-aspect/src/main/java/com/xcs/spring/MyTestService.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.xcs.spring;
-
-import org.springframework.stereotype.Service;
-
-@Service
-public class MyTestService {
-
- public void test() {
- System.out.println("test");
- }
-}
diff --git a/spring-aop/spring-aop-aspectj-before/pom.xml b/spring-aop/spring-aop-aspectj-before/pom.xml
deleted file mode 100644
index 3bb391a..0000000
--- a/spring-aop/spring-aop-aspectj-before/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- com.xcs.spring
- spring-aop
- 0.0.1-SNAPSHOT
-
-
- 4.0.0
- spring-aop-aspectj-before
-
-
\ No newline at end of file
diff --git a/spring-aop/spring-aop-aspectj-declareParents/pom.xml b/spring-aop/spring-aop-aspectj-declareParents/pom.xml
deleted file mode 100644
index c4f0e11..0000000
--- a/spring-aop/spring-aop-aspectj-declareParents/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- com.xcs.spring
- spring-aop
- 0.0.1-SNAPSHOT
-
-
- 4.0.0
- spring-aop-aspectj-declareParents
-
-
\ No newline at end of file
diff --git a/spring-aop/spring-aop-aspectj-pointcut/pom.xml b/spring-aop/spring-aop-aspectj-pointcut/pom.xml
deleted file mode 100644
index cac648c..0000000
--- a/spring-aop/spring-aop-aspectj-pointcut/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- com.xcs.spring
- spring-aop
- 0.0.1-SNAPSHOT
-
-
- 4.0.0
- spring-aop-aspectj-pointcut
-
-
\ No newline at end of file