Spring Boot 3.4.x重启后Aspect未触发(3.3.10正常)
Spring Boot 3.4.0 下多租户切面偶尔未触发问题
问题现象
基于Spring Boot 3.4.0开发的应用中,TenantServiceAspect切面用于拦截Repository方法调用,通过Hibernate过滤器实现多租户过滤。该切面在Spring Boot 3.3.10中运行正常,但偶尔在高负载下重启应用后,部分Repository方法(如findByCode)的beforeExecution()方法不会触发。经排查,问题根源是重启时请求在Spring Boot未完全就绪时到达导致。
环境信息
- Spring Boot版本:3.4.0
- Java版本:21
相关代码
Batch Rest服务
@RestController @RequiredArgsConstructor @RequestMapping("batch") public class BatchService { private final BatchBusinessService batchBusinessService; @GetMapping(value = "/findBatchByCode", produces = {MediaType.APPLICATION_JSON_VALUE}) ResponseEntity<ServiceResponse<BatchDto>> findBatchByCode(@RequestParam("code") String code) { return buildResponseEntity(batchBusinessService.findBatchByCode(code)); }; }
BatchBusinessService类
package com.example.batch.service; import com.example.batch.data.domain.Batch; import com.example.batch.data.dto.BatchDto; import com.example.batch.data.repository.BatchRepository; import com.example.batch.mapper.BatchMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor public class BatchBusinessService { private final BatchRepository batchRepository; private final BatchMapper mapper; public BatchDto findBatchByCode(String code) { Batch batch = batchRepository.findByCode(code).orElse(null); return mapper.toDto(batch); } }
BatchRepository接口
package com.example.batch.data.repository; import com.example.batch.data.domain.Batch; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Repository; import java.util.Optional; @Repository public interface BatchRepository extends JpaRepository<Batch, Long>, JpaSpecificationExecutor<Batch> { Optional<Batch> findByCode(String code); }
Aspect类
package com.example.framework.multitenancy.aspect; import com.example.logger.LogFactory; import com.example.logger.Logger; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.hibernate.Filter; import org.hibernate.Session; import org.springframework.stereotype.Component; @Aspect @Component public class TenantServiceAspect { private static final Logger LOGGER = LogFactory.getLogger(TenantServiceAspect.class); @PersistenceContext public EntityManager entityManager; public TenantServiceAspect() {} @Pointcut("execution(* org.springframework.data.jpa.repository.JpaRepository.*(..))") void isRepository() {} @Pointcut("execution(public * com.example..*.repository..*(..))") void isCustomRepository() {} @Before("(isCustomRepository() || isRepository())") public void beforeExecution(JoinPoint joinPoint) { LOGGER.warn("TenantServiceAspect triggered for method: {}", joinPoint.getSignature()); Filter filter = ((Session)this.entityManager.unwrap(Session.class)).enableFilter("companyFilter").setParameter("companyId", 1L); filter.validate(); } }
排查发现
- AspectJ版本差异:Spring Boot 3.3.10使用aspectjweaver 1.9.23,Spring Boot 3.4.0+(含3.4.3)降级为aspectjweaver 1.9.22.1。
- 依赖变更:Spring Boot 3.4.0起,
spring-boot-starter-data-jpa默认不再包含spring-boot-starter-aop依赖,官方发布说明明确移除了该依赖。 - 怀疑上述变更导致AOP支持在应用重启、高负载场景下出现不一致,进而引发切面偶尔未触发的问题。
建议解决方案
- 手动添加
spring-boot-starter-aop依赖,确保AOP功能完整加载:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> - 升级AspectJ版本至1.9.23或更高,覆盖Spring Boot 3.4.0默认版本:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.23</version> </dependency> - 配置应用启动防护:利用Spring Boot的
ApplicationReadyEvent配合网关/负载均衡器的健康检查机制,确保容器完全初始化后再接收外部请求,避免未就绪时处理请求。
内容的提问来源于stack exchange,提问作者kernel
相关产品推荐
相关产品推荐

