应用启动完成之前或者之后,我们需要拿数据库中的一些数据加载到本地缓存中。这些数据一般都是不经常变更而且有被经常读取的,并且数据量不是很大的。这样操作可以减少一些数据库的压力。下面是我们常用的实现方式,具体的要用那种,看对应各自应用的设计和需求。
使用@PostConstruct
注解
在需要加载数据的组件中,可以使用@PostConstruct
注解的方法,该方法会在Spring容器初始化该类之后自动调用
import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CacheInitializer { @Autowired private YourRepository yourRepository; // 假设你有一个访问数据库的Repository @Autowired private CacheManager cacheManager; // 假设你使用Spring Cache进行缓存管理 @PostConstruct public void init() { // 从数据库中获取数据 List<YourData> dataList = yourRepository.findAll(); // 将数据加载到缓存中 dataList.forEach(data -> { cacheManager.getCache("yourCacheName").put(data.getId(), data); }); } }
实现InitializingBean接口
它只包含一个方法 afterPropertiesSet()
。当一个 bean 的所有属性都被 Spring 容器设置之后(即通过依赖注入),afterPropertiesSet()
方法会被自动调用
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CacheInitializingBean implements InitializingBean { @Autowired private YourRepository yourRepository; // 假设你有一个访问数据库的Repository @Autowired private CacheManager cacheManager; // 假设你使用Spring Cache进行缓存管理 @Override public void afterPropertiesSet() throws Exception { // 在所有属性被设置之后,执行此方法 // 从数据库中获取数据并加载到缓存中 List<YourData> dataList = yourRepository.findAll(); dataList.forEach(data -> { cacheManager.getCache("yourCacheName").put(data.getId(), data); }); } }
注:使用 InitializingBean
接口与使用 @PostConstruct
注解的效果类似,但它们在 Spring 生命周期中的调用时机略有不同。@PostConstruct
注解的方法是在依赖注入完成后立即调用,而 InitializingBean
的 afterPropertiesSet()
方法则是在所有属性被设置之后调用。在大多数情况下,这两个选项可以互换使用,具体选择哪个取决于你的个人喜好和项目需求。
实现CommandLineRunner
接口
CommandLineRunner
接口提供了一个run
方法,该方法会在Spring Boot应用启动后立即执行。
import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class CacheRunner implements CommandLineRunner { @Autowired private YourRepository yourRepository; @Autowired private CacheManager cacheManager; @Override public void run(String... args) throws Exception { // 从数据库中获取数据并加载到缓存中 List<YourData> dataList = yourRepository.findAll(); dataList.forEach(data -> { cacheManager.getCache("yourCacheName").put(data.getId(), data); }); } }
实现ApplicationRunner
接口
ApplicationRunner
接口类似于CommandLineRunner
,但提供了更灵活的参数处理方式
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @Component public class CacheApplicationRunner implements ApplicationRunner { @Autowired private YourRepository yourRepository; @Autowired private CacheManager cacheManager; @Override public void run(ApplicationArguments args) throws Exception { // 从数据库中获取数据并加载到缓存中 List<YourData> dataList = yourRepository.findAll(); dataList.forEach(data -> { cacheManager.getCache("yourCacheName").put(data.getId(), data); }); } }
使用@EventListener
注解监听ApplicationReadyEvent
事件
Spring Boot在启动完成后会发布一个ApplicationReadyEvent
事件,你可以监听这个事件并在事件触发时执行加载数据的逻辑。
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class CacheInitializer { @Autowired private YourRepository yourRepository; @Autowired private CacheManager cacheManager; @EventListener(ApplicationReadyEvent.class) public void onApplicationReadyEvent() { // 从数据库中获取数据并加载到缓存中 List<YourData> dataList = yourRepository.findAll(); dataList.forEach(data -> { cacheManager.getCache("yourCacheName").put(data.getId(), data); }); } }
需要注意的是,加载数据的操作应该尽可能快地完成,避免延迟应用的启动时间。如果加载数据量非常大,你可能需要考虑异步加载或延迟加载的策略。