如何解决AOP无法修改DatabaseServiceImpl构造方法参数值的问题?
解决方案
你的核心问题有两个:
- Spring Bean的构造方法在容器初始化阶段执行,早于AOP拦截逻辑触发,因此构造时无法获取到AOP从Token中解析的
systemType; - 原
AspectDatabaseService中的systemType是全局变量,多线程环境下会出现请求间数据互相覆盖的并发问题。
以下是具体修改方案:
1. 重构AspectDatabaseService,使用ThreadLocal存储请求级别的systemType
将全局变量替换为ThreadLocal,确保每个请求的systemType独立存储,同时在请求结束后清理资源避免内存泄漏:
@Aspect @Configuration public class AspectDatabaseService { Logger logger = LoggerFactory.getLogger(AspectDatabaseService.class); private final ThreadLocal<Integer> systemTypeHolder = new ThreadLocal<>(); public int getSystemType() { Integer systemType = systemTypeHolder.get(); return systemType != null ? systemType : 0; } public void setSystemType(int systemType) { systemTypeHolder.set(systemType); } @Before("execution(* com.toshiba.mwcloud.gs.dbaas.service.impl.DatabaseServiceImpl.*(..))") public void before(JoinPoint joinPoint) { // 保留你原有从请求中获取Token、解析systemType的逻辑 HttpServletRequest request = getHttpServletRequest(); String token = extractTokenFromRequest(request); // 你的实现逻辑 int systemType = getSystemTypeFromToken(token); setSystemType(systemType); logger.info("before called {}", joinPoint.toString()); } // 新增后置通知,清理ThreadLocal @After("execution(* com.toshiba.mwcloud.gs.dbaas.service.impl.DatabaseServiceImpl.*(..))") public void after(JoinPoint joinPoint) { systemTypeHolder.remove(); } private HttpServletRequest getHttpServletRequest() { // 原有实现 } private int getSystemTypeFromToken(String token) { // 原有实现 } private String extractTokenFromRequest(HttpServletRequest request) { // 从request中提取Token的逻辑,比如从Header或参数中获取 } }
2. 修改DatabaseServiceImpl,动态选择业务实现类
移除构造方法中对databaseAbstractService的初始化逻辑,改为在每次业务方法调用时动态获取当前请求对应的实现类:
public class DatabaseServiceImpl { private final SingleDatabaseServiceImpl singleDatabaseService; private final MultiDatabaseServiceImpl multiDatabaseServiceImpl; private final OperatorDatabaseServiceImpl operatorDatabaseServiceImpl; private final AspectDatabaseService aspectDatabaseService; // 构造方法仅注入依赖,不做业务实现类选择 public DatabaseServiceImpl(SingleDatabaseServiceImpl singleDatabaseService, MultiDatabaseServiceImpl multiDatabaseServiceImpl, OperatorDatabaseServiceImpl operatorDatabaseServiceImpl, AspectDatabaseService aspectDatabaseService) { this.singleDatabaseService = singleDatabaseService; this.multiDatabaseServiceImpl = multiDatabaseServiceImpl; this.operatorDatabaseServiceImpl = operatorDatabaseServiceImpl; this.aspectDatabaseService = aspectDatabaseService; } // 新增私有方法,动态获取当前请求对应的业务实现 private DatabaseAbstractService getCurrentService() { int systemType = aspectDatabaseService.getSystemType(); if (systemType == SystemType.SINGLE.getCode()) { return singleDatabaseService; } else if (systemType == SystemType.MULTI.getCode()) { return multiDatabaseServiceImpl; } else { return operatorDatabaseServiceImpl; } } // 业务方法统一通过getCurrentService()调用对应实现 public void createDatabase(String dbName) { getCurrentService().createDatabase(dbName); } // 其他业务方法同理修改 public void deleteDatabase(String dbName) { getCurrentService().deleteDatabase(dbName); } }
方案说明
- 每次API请求进来时,AOP的
@Before通知会先执行,将当前请求的systemType存入ThreadLocal; - 业务方法调用时,通过
getCurrentService()动态获取对应实现类,此时systemType已经被AOP正确设置; ThreadLocal保证了多线程环境下每个请求的systemType互不干扰,避免并发问题;- 请求结束后
@After通知清理ThreadLocal,防止内存泄漏。
内容的提问来源于stack exchange,提问作者nghihoang2207
相关产品推荐
相关产品推荐

