闲着没事今天思考了一下,关于web 项目启动后的使用场景,最经典的是缓存使用场景,比如我们启动后需要加载数据一些信息作为项目运行的一个前提,具体简略实现如下:
开发首先思考技术点及其步骤:
1、使用spring 容器上下文
2、考虑初始化后的业务逻辑调用
3、缓存的设计
这里只是模拟,不是生产代码,只是一个思想的简述实现,项目结构如下:
具体关键代码
package com.szhome.cai.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @Author caizl
* @Description spring上线文工具类
* @Date 2024/01/05/9:34
* @Version 1.0
*/
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
}
/**
* 获取applicationContext
* @return
*/
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
}
这里使用到CommandLineRunner这个类,使用CommandLineRunner接口,可以在应用程序启动后执行一些必要的初始化操作,例如加载配置文件、初始化数据库连接、创建默认数据等。可以通过实现CommandLineRunner接口,并重写run方法来定义自己的初始化逻辑。由于有这些特性在这里正好满足使用场景
package com.szhome.cai.runner;
import com.szhome.cai.cache.AbstractCache;
import com.szhome.cai.utils.ApplicationContextUtil;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @Author caizl
* @Description springboot 启动后加载热点并进行缓存
* @Date 2024/01/05/9:41
* @Version 1.0
*/
@Component
//是否开启缓存
@ConditionalOnProperty(name = {"cache.init.enable"}, havingValue = "true", matchIfMissing = false)
public class CacheCommandRunner implements CommandLineRunner {
/**
* 解析参数
* @param args
* @throws Exception
*/
@Override
public void run(String... args) throws Exception {
ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
//获取缓存实现类
Map<String, AbstractCache> beansMap = applicationContext.getBeansOfType(AbstractCache.class);
//循环加载
for(Map.Entry<String, AbstractCache> cache : beansMap.entrySet()){
AbstractCache value = cache.getValue();
//AbstractCache bean = applicationContext.getBean(value.getClass());
value.init();
}
}
}
使用类的多肽性进行缓存类的实现
package com.szhome.cai.cache;
/**
* 缓存抽象类
*/
public abstract class AbstractCache {
/**
* 清除
*/
public abstract void clear();
/**
* 初始化
*/
public abstract void init();
/**
* 获取缓存
* @param <T>
* @return
*/
public abstract <T> T get(String key);
/**
* 重新加载
*/
public void reload(){
clear();
init();
}
}
package com.szhome.cai.cache;
import com.szhome.cai.utils.PropertyUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
/**
* @Author caizl
* @Description 热点信息缓存
* @Date 2024/01/05/9:33
* @Version 1.0
*/
@Component
@RequiredArgsConstructor
public class NewHotCache<T> extends AbstractCache{
Logger logger = Logger.getLogger(NewHotCache.class.getName());
private String newKey = "news";
@Value("hot.keys")
private String keys ;
//模拟缓存架构,如redis
public Map<String,Object> cache = new HashMap<>();
@Autowired
public PropertyUtil propertyUtil;
@Override
public void clear() {
//redisTemplate.delete(NEWS_KEY);
cache.clear();
}
@Override
public void init() {
System.out.println();
logger.info(keys + "热点初始化*************"+propertyUtil.getProperty("hot.keys"));
if(!cache.keySet().contains(newKey)){
//如果缓存没有则进行缓存
String cache_test_data = propertyUtil.getProperty("cache_test_data");
cache.put("news",cache_test_data);
}
/*
* if (Boolean.FALSE.equals(redisTemplate.hasKey(NEWS_KEY))) {
redisTemplate.opsForValue().set(NEWS_KEY, newsService.list(), 30, TimeUnit.MINUTES);
}
* */
}
@Override
public <T> T get(String key) {
/*
* if (Boolean.FALSE.equals(redisTemplate.hasKey(NEWS_KEY))) {
reload();
}
return (T) redisTemplate.opsForValue().get(NEWS_KEY);
* */
//如果没有当前key 则进行readlod
if(!cache.keySet().contains(key)){
reload();
}
return (T) cache.get(key);
}
}
测试代码
package com.szhome.cai;
import com.szhome.cai.cache.AbstractCache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class SpringbootstudyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SpringbootstudyApplication.class, args);
AbstractCache bean = run.getBean(AbstractCache.class);
Object news = bean.get("news");
System.out.println(news.toString());
}
}