当前位置: 首页 > news >正文

类内部方法调用,自注入避免AOP失效

代码

public abstract class AbstractSyncTaskHandler implements SyncTaskHandler, BeanSelfAware {protected AbstractSyncTaskHandler self;
/*** 注入自身对象.** @param proxyBean 代理bean*/
@Override
public void setSelf(Object proxyBean) {self = (AbstractSyncTaskHandler) proxyBean;
}
@Override
public void batchExecute(List<SyncTaskBO> syncTaskBOs, SyncTaskJobParamConfig syncTaskJobParamConfig) throws InterruptedException {List<SyncTaskBO> syncTaskBOS = self.refreshSyncTask(syncTaskBOs, syncTaskJobParamConfig);// 任务执行时间较长且并发较高的情况, 可能会出现上下文中日志记录文件错误的情况XxlJobContext xxlJobContext = XxlJobContext.getXxlJobContext();CountDownLatch countDownLatch = new CountDownLatch(syncTaskBOS.size());List<SyncTaskContext> contexts = CollUtil.newArrayList();syncTaskBOS.forEach(syncTaskBO -> {customerThreadPool.getSyncTaskPool().execute(() -> {XxlJobContext.setXxlJobContext(xxlJobContext);SyncTaskContext context = new SyncTaskContext();contexts.add(context);context.setSyncTaskBO(syncTaskBO);// 处理前置逻辑beforeExecute(context);boolean result = self.execute(context, syncTaskJobParamConfig);// 处理后置逻辑if (result) {afterExecute(context);}XxlJobContext.setXxlJobContext(null);countDownLatch.countDown();});});countDownLatch.await();batchMessageRule(contexts, syncTaskJobParamConfig);
}
@XLock(prefix = "ORDER_CENTER_REFRESH_TASK", keys = {"#syncTaskBOs[0].orderType", "#syncTaskBOs[0].type", "#syncTaskBOs[0].syncSystem", "#syncTaskJobParamConfig.handlerSuffix", "#syncTaskJobParamConfig.orderSources"},waitTime = 30, leaseTime = 30, errorMessage = "任务执行中,请勿重复执行")
public List<SyncTaskBO> refreshSyncTask(List<SyncTaskBO> syncTaskBOs, SyncTaskJobParamConfig syncTaskJobParamConfig) {
@XLock(prefix = "ORDER_CENTER", keys = {"#context.syncTaskBO.orderType", "#context.syncTaskBO.referenceId"}, waitTime = 30, leaseTime = 30, errorMessage = "任务执行中,请勿重复执行")
@Override
public boolean execute(SyncTaskContext context, SyncTaskJobParamConfig syncTaskJobParamConfig) {

疑问

为什么不通过这种方式注入

@Resource
protected AbstractSyncTaskHandler self;

## 为什么不通过 @Resource 注入自身

这是一个很好的问题。虽然表面上看起来使用 `@Resource` 注入自身更简洁,但实际上存在多个技术和设计层面的问题:

### 1. Spring容器循环依赖问题

#### 1.1 自注入会导致循环依赖
```java
@Component
public class AbstractSyncTaskHandler {
@Resource
protected AbstractSyncTaskHandler self; // 自身依赖自身 - 循环依赖

// ...
}
```


#### 1.2 Spring处理循环依赖的限制
- Spring默认只能解决单例Bean之间的setter循环依赖
- 构造器循环依赖会导致启动失败
- 自注入属于极端的循环依赖情况

### 2. 代理对象与原始对象的区别

#### 2.1 代理对象的特殊性
```java
// Spring创建的结构:
// 原始Bean: AbstractSyncTaskHandler (实际业务逻辑)
// 代理Bean: Proxy (包含AOP增强逻辑)

// 如果使用@Resource注入自身:
@Resource
protected AbstractSyncTaskHandler self; 
// 注入的可能是原始对象,而不是代理对象
// 这样AOP注解(@XLock)仍然不会生效
```


#### 2.2 自注入机制的优势
```java
// 通过setSelf方式:
@Override
public void setSelf(Object proxyBean) {
self = (AbstractSyncTaskHandler) proxyBean; // 确保获得的是代理对象
}
```


### 3. 抽象类的特殊性

#### 3.1 抽象类无法直接实例化
```java
// AbstractSyncTaskHandler是抽象类
public abstract class AbstractSyncTaskHandler implements SyncTaskHandler, BeanSelfAware {
// ...
}

// @Resource无法直接注入抽象类实例
```


#### 3.2 实际注入的是具体子类
```java
// 实际运行时,注入的是具体子类的代理对象
// 如: SalesCreateSyncTaskHandler的代理对象
```


### 4. Spring生命周期考虑

#### 4.1 Bean创建时机问题
```java
// 使用@Resource方式可能在Bean完全初始化前就尝试注入
// 导致注入失败或注入不完整的Bean

// 而setSelf在Bean完全初始化后由容器调用
// 确保注入的是完整可用的代理对象
```


### 5. 设计模式对比

#### 5.1 @Resource方式的问题
```java
@Component
public abstract class AbstractSyncTaskHandler {
@Resource
protected AbstractSyncTaskHandler self; // 问题:可能注入原始对象而非代理对象

public void methodA() {
// AOP注解可能不生效
}

public void methodB() {
self.methodA(); // 可能绕过AOP
}
}
```


#### 5.2 setSelf方式的优势
```java
@Component
public abstract class AbstractSyncTaskHandler implements BeanSelfAware {
protected AbstractSyncTaskHandler self; // 由容器在适当时机注入代理对象

@Override
public void setSelf(Object proxyBean) {
// 确保注入的是Spring代理对象
self = (AbstractSyncTaskHandler) proxyBean;
}

@XLock(...)
public void methodA() {
// AOP注解生效
}

public void methodB() {
self.methodA(); // 通过代理调用,AOP生效
}
}
```


### 6. 实际验证

如果尝试使用 `@Resource` 注入自身,很可能会遇到以下问题:
1. Spring启动时报循环依赖错误
2. 注入的不是代理对象,导致AOP失效
3. 抽象类无法直接注入的问题

### 总结

使用 [setSelf](file://C:\Users\NLDS\workspace\cloud-order\order-portal\src\main\java\com\cloud\order\sync\handler\AbstractSyncTaskHandler.java#L465-L468) 方法而非 `@Resource` 注入自身的原因:

1. **避免循环依赖**:防止Spring容器启动时出现循环依赖问题
2. **确保代理对象**:保证获得的是包含AOP增强的代理对象而非原始对象
3. **生命周期控制**:在Bean完全初始化后才进行注入
4. **抽象类兼容性**:正确处理抽象类的注入问题
5. **设计模式标准**:这是Spring框架推荐的处理同类调用AOP失效的标准解决方案

这是Spring生态系统中解决AOP代理调用问题的成熟方案,具有良好的可靠性和可维护性。

http://www.xdnf.cn/news/1246375.html

相关文章:

  • RK3568 Linux驱动学习——字符设备驱动开发
  • 森赛睿科技成为机器视觉产业联盟会员单位
  • C++ - 仿 RabbitMQ 实现消息队列--服务端核心模块实现(六)
  • Vue.js 教程
  • css3属性总结和浏览器私有属性
  • Matplotlib(六)- 坐标轴定制
  • 【视觉识别】Ubuntu 22.04 上安装和配置 TigerVNC 鲁班猫V5
  • 技术与情感交织的一生 (十一)
  • 漏洞分析:90分钟安全革命
  • 原型模式在C++中的实现与面向对象设计原则
  • vue3 计算属性
  • 前端实现Excel文件的在线预览效果
  • 10-红黑树
  • LINUX 85 SHElL if else 前瞻 实例
  • Goby 漏洞安全通告| NestJS DevTools /inspector/graph/interact 命令执行漏洞(CVE-2025-54782)
  • 国内办公安全平台新标杆:iOA一体化办公安全解决方案
  • 机械学习--决策树(实战案例)
  • Linux和mysql练习题2
  • Electron-updater + Electron-builder + IIS + NSIS + Blockmap 完整增量更新方案
  • HTML 媒体元素概述
  • LeetCode 71~90题解
  • MongoDB 从3.4.0升级到4.0.0完整指南实战-优雅草蜻蜓I即时通讯水银版成功升级-卓伊凡|bigniu
  • Redis内存耗尽时的应对策略
  • # 【Java + EasyExcel 实战】动态列 + 公式备注 Excel 模板导出全流程(附完整代码)
  • 分布式文件系统06-分布式中间件弹性扩容与rebalance冲平衡
  • PromptPilot搭配Doubao-seed-1.6:定制你需要的AI提示prompt
  • 行为模式-模板方法模式
  • 脚手架开发-准备配置-配置文件的准备项目的一些中间件
  • 超轻量级通用人脸检测模型解析:1MB以下的AI如何实现实时检测
  • VUE-第二季-02