说明: 我们有可能遇到,当我们项目启动的时候,我们就想预热一部分的缓存的场景,所以我们要创建在项目启动时就加载缓存的模块!
1. 定义缓存的抽象类AbstractCache
定义数据预热的规则
package com.ssm.redis.init;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
//@Component把类注入到spring容器中使用Component(Service Repository/Mapper Controller)
//@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法
@Component
public abstract class AbstractCache { //只定义预热缓存用到的方法
public abstract void initCache(); //初始化缓存
public abstract <T> T getCache();//获取cache (返回值任意类型,定义泛型T,要先声明<T>)
public abstract void clearCache();//清除缓存
public void reloadCache() { //重载缓存
clearCache();
initCache();
}
}
2. 实现需要进行缓存的类
说明: 此处实现缓存的类在业务模块中创建!
package com.ssm.user.cache;
import com.ssm.redis.init.AbstractCache;
import com.ssm.redis.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserCache extends AbstractCache {
private static final String USER_CACHE_KEY = "USER";
@Autowired
private RedisUtil redisUtil;
@Override
public void initCache() {
//可以跟数据库联动
redisUtil.set(USER_CACHE_KEY, "18");
}
@Override
public <T> T getCache() {
if(!redisUtil.exist(USER_CACHE_KEY)) { //不存在重新加载
reloadCache();
}
return (T) redisUtil.get(USER_CACHE_KEY); //存在,直接返回
}
@Override
public void clearCache() {
redisUtil.del(USER_CACHE_KEY);
}
}
3. 定义SpringContextUtil类来获取ApplicationContext
说明: 当一个类实现了ApplicationContextAware接口之后,这个类就可以方便的获得ApplicationContext对象(Spring上下文),Spring发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContext(参数)方法,调用该方法时,会将容器本身ApplicationContext对象作为参数传递给该方法。
package com.ssm.tool;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Map;
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationCtxt;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//实现接口后,会执行该set方法。我们在这里把applicationContext对象赋值到自己创建的applicationCtxt对象上
applicationCtxt = applicationContext;
}
public static ApplicationContext getApplicationCtxt() {
//applicationCtxt为private,外部想调用要二次封装get方法
return applicationCtxt;
}
public static Object getBean(Class type) throws BeansException {
//getBean 获取指定类的上下文(属性、方法等)
return applicationCtxt.getBean(type);
}
4. 启动并初始化缓存InitCache
说明: 在使用SpringBoot构建项目时,我们通常有一些预先数据的加载。那么SpringBoot提供了CommandLineRunner方式来实现,CommandLineRunner是一个接口,我们需要时,只需实现该接口就行(如果存在多个加载的数据,我们也可以使用@Order注解来排序)
package com.ssm.redis.init;
import com.ssm.tool.SpringContextUtil;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Map.Entry;
@Component
@ConditionalOnProperty(name = {"init.cache.enable"}, havingValue = "true") //符合规则的模块才预热数据
public class initCache implements CommandLineRunner {
@Override
public void run(String... args) throws Exception { //项目启动后会立即执行该方法(数据初始化、发送通知或者执行一些定时任务)
//预热数据,抽象类AbstractCache有实现类,利用SpringContextUtil获取AbstractCache类的所有实现类,遍历即可
ApplicationContext applicationContext = SpringContextUtil.getApplicationCtxt();
//getBeansOfType获取一个接口下所有实现类
Map<String, AbstractCache> beansMap = applicationContext.getBeansOfType(AbstractCache.class);
if(!beansMap.isEmpty()) {
for(Entry<String, AbstractCache> bean : beansMap.entrySet()) {
// 获取AbstractCache的子类(实现缓存方法的类),并调用其initCache()方法
AbstractCache abstractCache = (AbstractCache) SpringContextUtil.getBean(bean.getValue().getClass());
abstractCache.initCache();
};
}
System.out.println("缓存成功....");
}
}