Spring Boot读取实时更新JSON文件并同步至数据库问题求助
问题解决:Spring Boot定时读取更新后的JSON文件并同步到数据库
核心问题分析
- 读取旧数据的原因:
getResourceAsStream()读取的是类加载器缓存的资源内容,而非实时的文件系统文件。当你更新resources/json/file.json时,类加载器不会自动刷新缓存,因此始终读取启动时的旧数据。 - MasterService为null的原因:手动
new的类(如MyRunner)不属于Spring容器管理的Bean,Spring无法自动注入依赖,导致masterService为空。
解决方案
1. 修改文件读取逻辑,读取实时文件系统内容
替换getResourceAsStream()为直接读取文件系统的文件,推荐两种方式:
方式1:读取类路径下的文件(开发环境适用)
使用ClassPathResource获取实际文件路径,适用于本地开发环境:
@Autowired private ResourceLoader resourceLoader; @Scheduled(fixedRate=90000) public void readFile() { ObjectMapper mapper = new ObjectMapper(); TypeReference<List<Master>> typeReference = new TypeReference<List<Master>>(){}; try { ClassPathResource resource = new ClassPathResource("json/file.json"); File file = resource.getFile(); List<Master> users = mapper.readValue(file, typeReference); System.out.println("users "+users); masterService.save(users); System.out.println("Saved"); } catch (IOException e){ System.out.println("Unable to save users: " + e.getMessage()); e.printStackTrace(); } }
方式2:使用外部文件路径(推荐,适配生产环境)
将JSON文件写入外部目录而非resources下(jar包内部资源无法修改),配置固定外部路径:
@Scheduled(fixedRate=90000) public void readFile() { ObjectMapper mapper = new ObjectMapper(); TypeReference<List<Master>> typeReference = new TypeReference<List<Master>>(){}; try { // 外部文件路径,可配置在application.properties中 File file = new File("./data/json/file.json"); // 确保父目录存在,避免文件写入失败 file.getParentFile().mkdirs(); List<Master> users = mapper.readValue(file, typeReference); System.out.println("users "+users); masterService.save(users); System.out.println("Saved"); } catch (IOException e){ System.out.println("Unable to save users: " + e.getMessage()); e.printStackTrace(); } }
2. 解决依赖注入为null的问题
确保需要注入依赖的类由Spring容器管理,不要手动new:
步骤1:给自定义类添加Spring注解
比如MyRunner类添加@Component,让Spring扫描并管理:
@Component public class MyRunner { private final MasterService masterService; // 构造注入,Spring自动注入依赖 public MyRunner(MasterService masterService) { this.masterService = masterService; } public void runTask() { // 这里可以安全调用masterService的方法 } }
步骤2:通过Spring容器获取Bean
在主应用类中,不要手动new MyRunner,而是从Spring上下文获取:
@SpringBootApplication @EnableScheduling @EnableTransactionManagement public class ReadAndWriteJsonApplication { @Autowired private MasterService masterService; @Autowired private MyRunner myRunner; public static void main(String[] args) { ApplicationContext context = SpringApplication.run(ReadAndWriteJsonApplication.class, args); // 从上下文获取Bean MyRunner myRunner = context.getBean(MyRunner.class); myRunner.runTask(); } // 或者使用@PostConstruct在应用启动后执行 @PostConstruct public void init() { myRunner.runTask(); } // ... 定时任务方法 }
3. 优化依赖注入规范
MasterService中同时使用了字段注入和构造注入,建议统一使用构造注入(更安全、符合Spring规范):
@Service public class MasterService { private final MasterRepository masterRepository; // 构造注入,Spring 4.3+无需添加@Autowired public MasterService(MasterRepository masterRepository) { this.masterRepository = masterRepository; } public Iterable<Master> list() { return masterRepository.findAll(); } public Master save(Master master){ return masterRepository.save(master); } public Iterable<Master> save(List<Master> masters) { return masterRepository.saveAll(masters); } }
内容的提问来源于stack exchange,提问作者Andino
相关产品推荐
相关产品推荐

