SpringBoot实现冷数据预热功能
实现原理
- 实现ServletContextListener接口,重写contextInitialized()方法,当SpringContext初始化完成后,会调用该方法
- 在该方法里实现业务逻辑
示例
- 定义冷数据预热业务类,实现ServletContextListener
import com.alibaba.fastjson.JSONObject;
import gk.springboot.preheat.dao.UserDao;
import gk.springboot.preheat.model.UserInfo;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.hash.Jackson2HashMapper;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Component
@AutoConfigureAfter(value = RedisTemplateConfig.class)
public class PreHeatUserToRedis implements ServletContextListener {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private UserDao userDao;
public static final String USER_KEY_PREFIX = "user:";
@Override
public void contextInitialized(ServletContextEvent sce) {
Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> keysTmp = new HashSet<>();
Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(USER_KEY_PREFIX + "*").count(1000).build());
while (cursor.hasNext()) {
keysTmp.add(new String(cursor.next()));
}
return keysTmp;
});
redisTemplate.unlink(keys);
List<UserInfo> users = userDao.getAllUserInfo();
users.forEach(u -> redisTemplate.opsForHash().putAll(
USER_KEY_PREFIX + u.getId(),
JSONObject.parseObject(JSONObject.toJSONString(u)).getInnerMap()
)
);
}
}
- 为了解决Spring中redisTemplate写数据出现乱码问题,需要重新对redisTemplate重新配置序列化对象
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisTemplateConfig {
@Bean(value = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericFastJsonRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
- 其他的UserDao、UserController、UserService类就是正常写,没有特别注意点。SpringBoot的启动类也没需要加特殊注解。
测试
- 在Tomcat启动前,就已完成数据加载到redis中
- redis中也同样能看到该2条数据