spring boot 集成了常用的cache实现
- Generic
- JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
- EhCache 2.x
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Simple
具体可看Spring boot cache文档
** 使用也极为简单。基本2个注解 **
- @EnableCaching
- @Cacheable
基本使用
-
工具 Eclipse STS
代码编写
@SpringBootApplication
@EnableCaching
public class SpringDemoCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDemoCacheApplication.class, args);
}
}
public class Address implements java.io.Serializable {
private static final long serialVersionUID = 5287789368637836326L;
public Address() {
}
private String sno;
private String country;
private String state;
public Address(String sno, String country, String state) {
this.sno = sno;
this.country = country;
this.state = state;
}
@Override
public String toString() {
return sno + "," + country + "," + state;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
@Component
public class AddressService {`
private static final Logger logger = LoggerFactory.getLogger(AddressService.class);
private List addressList = new ArrayList();
public AddressService() {
init();
}
private void init() { //模拟数据
addressList.add(new Address("10010", "China", "NJ"));
addressList.add(new Address("10020", "China", "BJ"));
addressList.add(new Address("10030", "China", "HZ"));
}
@Cacheable(value = "birds_cache2")
public Address findAddress(String sno) {
logger.info("----find----" + sno);
for (Address address : addressList) {
if (sno.equals(address.getSno())) {
return address;
}
}
return null;
}
}
@Component
public class CacheRunner implements CommandLineRunner { //测试
private static final Logger logger = LoggerFactory.getLogger(CacheRunner.class);
@Autowired
private AddressService addressService;
public CacheRunner() {
}
@Override
public void run(String... args) throws Exception {
logger.info(addressService + "");
logger.info("" + addressService.findAddress("10010"));
logger.info("" + addressService.findAddress("10020"));
logger.info("" + addressService.findAddress("10030"));
//后面3个打印 取缓存数据
logger.info("" + addressService.findAddress("10010"));
logger.info("" + addressService.findAddress("10020"));
logger.info("" + addressService.findAddress("10030"));
}
}
-
结果
配合redis
- 默认application.properties 如果没有配置 则使用最简单的 concurrent maps
- 配置redis
spring.redis.host = 192.168.2.20
spring.redis.port = 6379
spring.cache.cache-names=birds_cache2,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=8s
#如果有redis上面的caffeine缓存将失效,直接存储到redis中
spring.cache.redis.time-to-live=8000
-
结果
(测试时,修改了几次cache名)
自定义key
- 默认key是用 缓存名::参数值
- 实现 org.springframework.cache.interceptor.KeyGenerator
@Configuration
@Component("birds_key_gen")
public class CustomCacheKey implements KeyGenerator {
private static final Logger logger = LoggerFactory.getLogger(CustomCacheKey.class);
public CustomCacheKey() {
}
@Override
public Object generate(Object target, Method method, Object... params) {
logger.info("call CustomCacheKey:" + target.getClass().getSimpleName() + " " + method.getName() + " " + params[0]);
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getSimpleName())
.append("_")
.append(method.getName())
.append("_")
.append(params[0]);
return sb.toString();
}
}
- 修改service方法
@Cacheable(value = "birds_cache_cuskey",keyGenerator = "birds_key_gen")
public Address findAddress(String sno) {
logger.info("----find----" + sno);
for (Address address : addressList) {
if (sno.equals(address.getSno())) {
return address;
}
}
return null;
}
-
运行后结果
如何自定义自己的cache
可以通过系统源码了解基本的
-
基本的cache组件配置
自定义CacheManager
@Component
public class MyCacheManager implements CacheManager {
@Autowired
private MyCustomCache myCustomCache;
public MyCacheManager() {
}
@Override
public Cache getCache(String name) {
System.err.println("====cache name====" + name);//如果有多个 需要通过 name获取对应的cache instance
return myCustomCache; //直接返回,就一个Cache
}
@Override
public Collection getCacheNames() { //没有用上
System.out.println("getCacheNames");
return Arrays.asList(new String[] {"my_cache1","my_cache2"});
}
}
- Cache实例
@Component
public class MyCustomCache implements Cache {
private static final Logger logger = LoggerFactory.getLogger(MyCustomCache.class);
static final ConcurrentHashMap cacheMap = new ConcurrentHashMap();
public MyCustomCache() {
logger.info("init cache....");
}
@Override
public String getName() {
return "";
}
@Override
public Object getNativeCache() {
return cacheMap;
}
@Override
public ValueWrapper get(Object key) {
Object obj = cacheMap.get(key + "");
if (obj != null) {
logger.info("hit cache:" + key);
return new SimpleValueWrapper(obj);
}
return null;
}
@Override
public T get(Object key, Class type) {
logger.info("get cache1...");
return (T) cacheMap.get(key + "");
}
@Override
public T get(Object key, Callable valueLoader) {
logger.info("get cache2...");
return (T) cacheMap.get(key + "");
}
@Override
public void put(Object key, Object value) {
logger.info("put cache2...");
cacheMap.put(key + "", value);
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
logger.info("putIfAbsent...");
return null;
}
@Override
public void evict(Object key) {
cacheMap.remove(key);
}
@Override
public void clear() {
}
}
-
运行结果
总结
自定义大部分情况下用不上,自带的基本够用
自定义还需要实现过期功能
-
项目最终结构
(有问题,欢迎指出)