Introducing the use of caching in SpringBoot projects, let's start with an introduction to Spring's cache abstraction and JSR107. This blog is a note I made after learning Silicon Valley videos and referring to other blogs for learning purposes only. This blog will provide more detailed information about Spring's cache annotations, how to use them to implement caching in Springboot projects, and also how to reference them.Cache in Redis for learning reference only
@[toc]
1. Cache abstraction of Spring
1.1. Cache abstract definition
Spring has defined org.springframework.cache.Cache since 3.1 Unify different caching technologies with the org.springframework.cache.CacheManager interface; and support the use of Java Caching (JSR-107) annotations to simplify our cache development.Spring Cache is responsible for maintaining the abstraction layer only, and the implementation depends on your technical choice.Decoupling cache processing and caching techniques.
1.2. Important interfaces
- Cache: Cache Abstract specification interface, cache implementations are RedisCache, EhCacheCache, ConcurrentMapCache, etc.
- Cache Manager: Cache Manager, which manages the life cycle of a Cache
II. JSR107
2.1, JSR107 Core Interface
Java Caching (JSR-107) defines five core interfaces: CachingProvider, CacheManager, Cache, Entry, and Expiry.
- CachingProvider: Create, configure, acquire, manage, and control multiple CacheManager s
- CacheManager: Create, configure, acquire, manage, and control multiple uniquely named Caches that exist within the context of CacheManager.A CacheManager corresponds to only one CachingProvider
- Cache: is managed by Cache Manager, which manages the life cycle of Cache. Cache exists in the context of Cache Manager and is a map-like data structure that temporarily stores key-indexed values.A Cache is owned by only one CacheManager
- Entry: is a key-value pair stored in a Cache
- Expiry: Each entry stored in a Cache has a defined expiration date.Once this time is exceeded, the entries will automatically expire, after which they will not be accessible, updated, and deleted.Cache validity can be set through ExpiryPolicy
2.2, JSR107 Diagram
Reference the illustration in the Silicon Valley video courseware:
3. Spring Cache Use
3.1. Introduction to Important Notes
Before you go through the example practice, give a brief introduction to the important cache annotations provided by Spring
- @Cacheable: For method configurations, the results of a method can be cached based on its request parameters
- @CacheEvict: Empty Cache
- @CachePut: Calls methods and updates cached data
- @EnableCaching: Turn on annotation-based caching
- @Caching: Define complex caching rules
3.2. Environmental Preparation
ok, this blog is rewritten with a video example from Silicon Valley, illustrated with this classic example
Environmental preparation:
- maven environment
- IntelliJ IDEA Create two new tables:
DROP TABLE IF EXISTS `employee`; CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `lastName` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `gender` int(2) DEFAULT NULL, `d_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `department`; CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `departmentName` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.3. Introducing the spring-boot-starter-cache module
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
3.4. Key Note Example Practice
3.4.1,@EnableCaching
@EnableCaching turns on annotation-based caching
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching public class SpringbootCacheApplication { public static void main(String[] args) { SpringApplication.run(SpringbootCacheApplication.class, args); } }
3.4.2, @Cacheable comment
The role of the @Cacheable annotation, which was also outlined earlier, is primarily for method configuration, which caches the results based on the method's request parameters, and describes the main properties of the annotation
- cacheNames/value: Specifies the name of the cache component as an array
- Key: the key used for caching data, which determines that the cache can be specified with a unique key; eg: writing SpEL; #id, value of parameter id, #a0 (first parameter), #p0 (same meaning as a0), #root.args[0]
- Generator for keyGenerator: key; the component id of the generator for key can be specified by itself (Note: key/keyGenerator: Use both; not both)
- cacheManager: Specify the cache manager; or cacheResolver specifies the get parser
- Condition: Cache only when conditions are specified; with the SpEl expression, eg:condition ='#a0>1': Cache only when the value of the first parameter is >1
- Unless: denies caching; when unless specifies a condition that is true, the return value of the method will not be cached; eg:unless ='#a0!=2 ": If the value of the first parameter is not 2, the result is not cached;
- sync: whether to use asynchronous mode
@Cacheable(value = {"emp"}, /*keyGenerator = "myKeyGenerator",*/key = "#id",condition = "#a0>=1",unless = "#a0!=2") public Employee getEmp(Integer id) { Employee employee = this.employeeMapper.getEmpById(id); LOG.info("query{}No. Employee Data",id); return employee; }
Custom keyGenerators can also be used here, using the property keyGenerator = "myKeyGenerator"
Define a @Bean class to add KeyGenerator to the Spring container
@Configuration public class CacheConfig { @Bean(value = {"myKeyGenerator"}) public KeyGenerator keyGenerator(){ return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { return method.getName()+"["+ Arrays.asList(params).toString()+"]"; } }; } }
3.4.3, @CachePut comment
The @CachePut comment is also a comment for caching, but there is a clear difference between caching and @Cacheable in that it calls the method and updates the cached data, i.e. updates the cache synchronously after performing a method operation. So this primary key is often used for updating operations and also for querying. There are many similar properties for the primary key and @Cacheable. See the @link @CachePut source code for details
/** * @CachePut: Call method and update cache data; update cache synchronously * Modify data and update cache */ @CachePut(value = {"emp"}, key = "#result.id") public Employee updateEmp(Employee employee){ employeeMapper.updateEmp(employee); LOG.info("To update{}No. Employee Data",employee.getId()); return employee; }
3.4.4, @CacheEvic comment
Main attributes:
- key: specify the data to be cleared
- allEntries = true: Specifies to clear all data in this cache
- beforeInvocation = false: Default means cache cleanup is performed after method execution
- beforeInvocation = true: Represents that the cache cleanup operation was performed before the method was run
@CacheEvict(value = {"emp"}, beforeInvocation = true,key="#id") public void deleteEmp(Integer id){ employeeMapper.deleteEmpById(id); //int i = 10/0; }
3.4.5, @Caching comment
@Caching is used to define complex caching rules that integrate @Cacheable with @CachePut
// @Caching defines complex caching rules @Caching( cacheable = { @Cacheable(/*value={"emp"},*/key = "#lastName") }, put = { @CachePut(/*value={"emp"},*/key = "#result.id"), @CachePut(/*value={"emp"},*/key = "#result.email") } ) public Employee getEmpByLastName(String lastName){ return employeeMapper.getEmpByLastName(lastName); }
3.4.6, @CacheConfig annotation
The @CacheConfig annotation can be used to extract the public configuration of the cache, then added to the class, eg:@CacheConfig(cacheNames = {"emp"},cacheManager = "employeeCacheManager")
Appendix Extensions: SpEL Expression Usage
Cache SpEL available metadata
Name | position | describe | Example |
---|---|---|---|
methodName | root object | Method name currently being invoked | #root.methodname |
method | root object | Method currently called | #root.method.name |
target | root object | Currently invoked target object instance | #root.target |
targetClass | root object | Class of the target object currently being invoked | #root.targetClass |
args | root object | Parameter list of currently invoked methods | #root.args[0] |
caches | root object | List of caches used by current method calls | #root.caches[0].name |
argument Name | Execution context | Parameters of the currently invoked method, such as findArtisan(Artisan artisan), can be obtained from #artsian.id | #artsian.id |
result | Evaluation context | Return value after method execution (only if the judgement after method execution is valid, such as beforeInvocation=false for unless cacheEvict) | #result |
4. Integrated Redis Cache
4.1. Environmental preparation
Based on the previous Spring caching environment, integrating redis introduces related configurations:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
Switch cache mode to Redis:spring.cache.type=redis
4.2. Redis configuration class implementation
RedisTemplate Configuration
@Resource private LettuceConnectionFactory lettuceConnectionFactory; @Bean @Primary public RedisTemplate<Object,Object> redisTemplate(){ RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<Object, Object>(); redisTemplate.setConnectionFactory(lettuceConnectionFactory); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = this.initJacksonSerializer(); // Set serialization rules for value and key redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; }
RedisCacheManager-related code can refer to the blog post, which already has a good encapsulation of the code, so this article does not copy the code
4.3, RestTemplate related operations
Use RestTemplate to manipulate redis
- 1. redisTemplate.opsForValue(); //Action string
- 2. redisTemplate.opsForHash(); //operation hash
- 3. redisTemplate.opsForList(); //operation list
- 4. redisTemplate.opsForSet(); //operation set
- 5. redisTemplate.opsForZSet(); //ordered set of operations
4.4. Caching Business Test
@Autowired DepartmentMapper departmentMapper; @Qualifier("redisCacheManager") @Autowired RedisCacheManager redisCacheManager; // @Cacheable(cacheNames = "dept",cacheManager = "redisCacheManager") // public Department getDeptById(Integer id){ // System.out.println("Query Department"+id); // Department department = departmentMapper.getDeptById(id); // return department; // } // Use the cache manager to get the cache and make api calls public Department getDeptById(Integer id){ LOG.info("query id by{}Employee information for",id); //Get a cache Cache deptCache = redisCacheManager.getCache("dept"); Department department = null; if(deptCache.get(id)==null){ department = departmentMapper.getDeptById(id); deptCache.put(id,department); } else { SimpleValueWrapper valueWrapper = (SimpleValueWrapper) deptCache.get(id); department = (Department)valueWrapper.get(); } return department; }
Of course, using the previous Spring primary key can also be cached. Reference Blog: Cache abstraction layer Spring cache real-time operations
Code sample download: github link