- 最近在项目中使用Ehcache作为jvm级别的缓存加快请求的响应速度。但是Ehcache需要在使用的时候才会去加载数据。这样在第一次请求的时候数据还是会打到数据库。基于此需要实现一个基于Ehcache的缓存预热的功能。
@Slf4j
@Data
public class PoliciesCacheLoader implements BootstrapCacheLoader {
private boolean asynchronous;
private RangerPolicyApiService policyApiService;
public PoliciesCacheLoader(boolean asynchronous,RangerPolicyApiService policyApiService){
this.asynchronous = asynchronous;
this.policyApiService = policyApiService;
}
@Override
public void load(Ehcache cache) throws CacheException {
if (asynchronous) {
BootstrapThread thread = new BootstrapThread(cache);
thread.start();
} else {
doLoad(cache);
}
}
@Override
public boolean isAsynchronous() {
return this.asynchronous;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
private void doLoad(Ehcache cache){
// 1、拼接查询Ranger的请求参数一次把所有的权限都查询出来在内存中进行操作减小数据库压力
Map map = new HashMap<>();
map.put(SearchFilter.SERVICE_NAME, "hive");
map.put(SearchFilter.POLICY_TYPE, 0);
map.put(SearchFilter.PAGE_SIZE,Integer.MAX_VALUE);
// 2、查询Ranger获取所有的权限项
List policies = policyApiService.list(map);
// 3、循环将数据load到内存中
for (RangerPolicy policy : policies) {
log.info("开始初始化权限项:{}",policy);
Map resources = policy.getResources();
RangerPolicy.RangerPolicyResource database = resources.get("database");
RangerPolicy.RangerPolicyResource table = resources.get("table");
if (database != null && table != null){
List databasevalues = database.getValues();
List tablevalues = table.getValues();
if (databasevalues.size() == 1 && !databasevalues.contains("*") && tablevalues.size() == 1 && !tablevalues.contains("*")){
List policyItems = policy.getPolicyItems();
if (CollectionUtils.isNotEmpty(policyItems)){
RangerPolicy.RangerPolicyItem rangerPolicyItem = policyItems.get(0);
List users = rangerPolicyItem.getUsers();
if (CollectionUtils.isNotEmpty(users)){
// 将初始化的数据加载到内存中
String key = databasevalues.get(0) + tablevalues.get(0) + users.get(0);
cache.put(new Element(key, Collections.singletonList(policy)));
log.info("权限项:{}初始化完成",policy);
}
}
}
}
}
}
private final class BootstrapThread extends Thread {
private final Ehcache cache;
public BootstrapThread(Ehcache cache) {
super("Bootstrap Thread for cache " + cache.getName());
this.cache = cache;
setDaemon(true);
setPriority(Thread.NORM_PRIORITY);
}
@Override
public final void run() {
try {
doLoad(cache);
} catch (RemoteCacheException e) {
log.warn("Error asynchronously performing bootstrap. The cause was: " + e.getMessage(), e);
}
}
}
}
public class PoliciesCacheLoaderFactory extends BootstrapCacheLoaderFactory {
@Value("${asynchronous.load.policy.data:false}")
private boolean asynchronous;
@Override
public PoliciesCacheLoader createBootstrapCacheLoader(Properties properties) {
return new PoliciesCacheLoader(asynchronous, SpringBeanUtils.getBean(RangerPolicyApiService.class));
}
}
@Component
public class SpringBeanUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringBeanUtils.applicationContext = applicationContext;
}
public static T getBean(Class type){
return applicationContext.getBean(type);
}
}
// xml中的配置
到此为止一个Ehcache缓存预热的功能就实现了



