SpringBoot+Spring-Data-JPA:每次请求时ArrayList/JSON对象重复填充
我之前处理过类似的场景,你遇到的重复填充问题,核心原因大概率是对Spring的Bean作用域理解不到位,或者Service内部的状态管理有问题,下面给你拆解原因和解决方案:
为什么会出现重复填充?
1. Controller是单例,但Prototype Service没有被正确获取
Spring中Controller默认是singleton作用域,也就是整个应用生命周期只有一个实例。如果你用@Autowired直接注入prototype作用域的Service,Controller只会在初始化时创建一次Service实例,后续所有请求都会复用这个Service——这就导致Service里的集合每次调用都会累加数据,自然返回的列表越来越长。
2. Service内部的状态没有重置
如果你的Service类里把存储Site的ArrayList定义成了成员变量,而不是在getItinerary方法内部创建,那不管Service是不是prototype,只要复用实例,集合里的数据就会不断叠加。
具体解决方案
方案一:让Controller每次请求都获取新的Prototype Service
因为Controller是单例,不能直接依赖注入prototype Bean,得用动态获取的方式:
方式1:使用@Lookup注解
在Controller里定义一个抽象方法来获取Service,Spring会动态实现这个方法,每次调用都返回新的Service实例:
@RestController public class SiteController { @Lookup protected SiteService getSiteService() { return null; // 占位,Spring会自动实现 } @RequestMapping("/getItinerary") public List<Site> getItinerary() { // 每次请求都拿到新的Service实例 SiteService service = getSiteService(); return service.getItinerary(); } }
方式2:通过ApplicationContext获取
直接注入ApplicationContext,每次请求时手动获取新的Service Bean:
@RestController public class SiteController { @Autowired private ApplicationContext context; @RequestMapping("/getItinerary") public List<Site> getItinerary() { SiteService service = context.getBean(SiteService.class); return service.getItinerary(); } }
方案二:重置Service内部的状态(最稳妥的辅助方案)
不管Service的作用域是什么,都不要把集合作为成员变量,而是在getItinerary方法内部创建新的集合,从数据库查询后直接填充并返回:
@Service @Scope("prototype") public class SiteService { @Autowired private SiteRepository siteRepository; public List<Site> getItinerary() { // 每次调用都创建新的集合,避免数据累加 List<Site> siteList = new ArrayList<>(); siteList.addAll(siteRepository.findAll()); return siteList; } }
这样即使Service实例被复用,每次调用方法都会生成全新的列表,不会出现重复数据。
方案三:排查数据库查询逻辑
最后可以确认下你的SiteRepository查询方法(比如findAll())是否返回了重复数据——比如数据库里本身有没有重复的Site记录,或者查询条件是否存在问题。可以在Service里加日志打印查询到的列表长度,排除数据库层面的问题。
内容的提问来源于stack exchange,提问作者javaland235

