刚刚接触Spring Cache功能,发现网上很多博客,都没有入门级应用介绍,所以花了一些时间整理了一下。关于cache基本功能用法,可自行百度。
一、工程准备
创建一个springboot工程
1.1、pom.xml
采用web服务进行校验
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.4.5</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
1.2、 入口函数
@SpringBootApplication
public class Hello {
public static void main(String[] args) {
SpringApplication.run(Hello.class, args);
}
}
1.3、web服务
@RestController
public class HelloController {
@Resource
private ComputerService service;
/**
* http://127.0.0.1:8080/hello
*/
@RequestMapping("/hello")
public String Hello() {
return "hello world";
}
/**
* http://127.0.0.1:8080/plus?a=1&b=2
*/
@RequestMapping("/plus")
public int Plus(@RequestParam int a, @RequestParam int b) {
return service.plus(a, b);
}
}
@Service
public class ComputerService {
private final static Logger logger = LoggerFactory.getLogger(ComputerService.class);
public int plus(int a, int b) {
logger.info("plus, a={}, b={}", a, b);
return a + b;
}
}
验证结果,会有日志输出:
2021-08-31 17:58:25.337 INFO 67530 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-08-31 17:58:25.337 INFO 67530 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-08-31 17:58:25.338 INFO 67530 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2021-08-31 17:58:25.360 INFO 67530 --- [nio-8080-exec-1] c.m.hello.service.ComputerService : plus, a=1, b=2
2021-08-31 17:58:28.553 INFO 67530 --- [nio-8080-exec-2] c.m.hello.service.ComputerService : plus, a=1, b=2
二、简单应用
要想应用cache功能,需要做如下操作:
1)注入CacheManager管理对象
2)启用cache功能 @EnableCaching
3)标注方法,@Cacheable
2.1、注入CacheManager管理对象
@Configuration
public class CacheConfig {
@Bean
public CacheManager createCacheManger() {
SimpleCacheManager mgr = new SimpleCacheManager();
List<Cache> caches = new ArrayList<>();
caches.add(new ConcurrentMapCache("plus")); //设置cache名称,这里需要注意,后面会用到
mgr.setCaches(caches);
return mgr;
}
}
2.2、启用@EnableCaching
在入口函数类,进行注入
@SpringBootApplication
@EnableCaching
public class Hello {
public static void main(String[] args) {
SpringApplication.run(Hello.class, args);
}
}
2.3、标注方法
@Service
public class ComputerService {
private final static Logger logger = LoggerFactory.getLogger(ComputerService.class);
@Cacheable(cacheNames = "plus", key = "#a")
public int plus(int a, int b) {
logger.info("plus, a={}, b={}", a, b);
return a + b;
}
}
运行查看效果,发现只有第一次会有打印:
2021-08-31 18:06:45.428 INFO 68983 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-08-31 18:06:45.428 INFO 68983 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-08-31 18:06:45.429 INFO 68983 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2021-08-31 18:06:45.458 INFO 68983 --- [nio-8080-exec-1] c.m.hello.service.ComputerService : plus, a=1, b=2
三、自定义cache
上面例子,使用的是spring自带的cache组件,当然也有开源组件比如redis的,但是如果自己实现一套cache应该怎么实现呢。这个并不是很复杂,下面一起看一下。
spring提供两个接口:Cache和CacheManager两个接口,这两个接口在spring中都实现。
public class CacheImpl implements Cache {
private final static Logger LOG = LoggerFactory.getLogger(CacheImpl.class);
private String name;
private Map<Object, Object> map = new ConcurrentHashMap<>();
public CacheImpl(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
@Override
public Object getNativeCache() {
return map;
}
@Override
public ValueWrapper get(Object o) {
Object v = map.get(o);
if (v != null) {
return new ValueWrapper() {
@Override
public Object get() {
LOG.info("get o");
return v;
}
};
} else {
return null;
}
}
@Override
public <T> T get(Object o, Class<T> aClass) {
LOG.info("get class");
Object v = this.map.get(o);
if (aClass != null && aClass == v.getClass()) {
return (T)v;
}
return null;
}
@Override
public <T> T get(Object o, Callable<T> callable) {
return null;
}
@Override
public void put(Object o, Object o1) {
LOG.info("PUT");
this.map.put(o, o1);
}
@Override
public void evict(Object o) {
this.map.remove(o);
}
@Override
public void clear() {
this.map.clear();
}
}
public class MyCacheManager implements CacheManager {
Map<String, Cache> maps = new HashMap<>();
@Override
public Cache getCache(String s) {
return maps.get(s);
}
@Override
public Collection<String> getCacheNames() {
return maps.keySet();
}
public void setCaches(List<Cache> caches) {
caches.forEach(e -> maps.put(e.getName(), e));
}
}
运行效果,与上面是一致的。