@EnableAspectJAutoProxy
...大约 3 分钟SpringBoot注解AOP智能协同云图库
🍂 智能协同云图库
@EnableAspectJAutoProxy(exposePro xy = true)有什么用?
它是启用基于AspectJ的 AOP 功能的意思,它会告诉 Spring 使用代理来处理带有 AOP 注解的类。
- 默认情况下,Spring 创建的代理对象是不可直接访问的,因为它是在 Spring 容器中管理的对象。
- 通过设置 exposeProxy = true,你可以在代码中访问到代理对象,
- 从而使得你能够在某些特殊情况下获取和操作代理对象。
举个例子:
我们有一个业务类 UserService
,里面有两个方法:
createUser()
:创建用户,同时调用sendNotification()
方法。sendNotification()
:发送通知。
假设我们有一个切面(LoggingAspect
)用来记录方法调用日志。
重点问题: 如果我们在 createUser()
方法内部直接调用 sendNotification()
,默认情况下 Spring AOP 不会拦截这个调用(因为内部方法调用不会经过代理对象)。 通过 exposeProxy = true
和 AopContext.currentProxy()
,我们可以在内部方法调用中获取代理对象,从而让切面正常工作。
1. 项目结构
src/main/java
├── AppConfig.java // Spring 配置类
├── UserService.java // 业务类
├── LoggingAspect.java // 切面类
└── MainApp.java // 启动类
2. 代码实现
2.1 Spring 配置类(启用 AOP 并暴露代理对象)
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.example") // 扫描当前包下的组件
@EnableAspectJAutoProxy(exposeProxy = true) // 启用 AOP,并暴露代理对象
public class AppConfig {
}
2.2 业务类(UserService)
在 createUser()
方法中,我们通过 AopContext.currentProxy()
获取代理对象并调用 sendNotification()
,从而触发切面增强。
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void createUser() {
System.out.println("正在创建用户...");
// 直接调用当前类的另一个方法
System.out.println("直接调用 sendNotification() 方法:");
sendNotification(); // 直接调用,不会触发切面
System.out.println("\n通过代理调用 sendNotification() 方法:");
// 获取当前代理对象并调用方法
UserService proxy = (UserService) AopContext.currentProxy();
proxy.sendNotification(); // 通过代理调用,会触发切面
}
public void sendNotification() {
System.out.println("正在发送通知...");
}
}
2.3 切面类(LoggingAspect)
切面会在 UserService
的方法执行前后记录日志。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.qtp.picture.UserService.*(..))")
public void logBefore() {
System.out.println("[日志] 方法执行开始。");
}
@After("execution(* com.qtp.picture.UserService.*(..))")
public void logAfter() {
System.out.println("[日志] 方法执行结束。");
}
}
2.4 启动类(MainApp)
启动 Spring 容器,获取 UserService
并调用方法。
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainApp {
public static void main(String[] args) {
// 加载 Spring 容器
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取 UserService Bean
UserService userService = context.getBean(UserService.class);
// 调用 createUser() 方法
userService.createUser();
}
}
3. 执行输出
运行 MainApp
,输出结果如下:
正在创建用户...
直接调用 sendNotification() 方法:
正在发送通知...
通过代理调用 sendNotification() 方法:
[日志] 方法执行开始。
正在发送通知...
[日志] 方法执行结束。
4. 总结
- 实际用途:在业务逻辑复杂、需要触发切面增强的内部方法调用时,这是非常有用的。通过
exposeProxy = true
暴露代理对象,然后使用AopContext.currentProxy()
获取当前代理对象,这样调用方法时就能触发切面逻辑。