In-depth understanding of the use and integration of Spring Cache (with source code analysis)
Personal development environment
Java environment: Jdk1.8.0_60
Compiler: IntelliJ IDEA 2019.1
Official springCache documentation: https://docs.spring.io/spring/docs/5.1. 9.RELEASE/spring-framework-reference/integration.html#cache
1. Spring cache abstract
Background of SpringCache In fact, the background is somewhat similar to Spring. Due to the bloated and inefficient Java EE system framework, low code observability, complex object creation and dependency relationships, the Spring framework has come out. At present, basically all Java back-end projects are inseparable from Spring or SpringBoot (further encapsulation and simplification of Spring) . Now that projects are facing more and more problems with high concurrency, and the application of various types of caches is also increasing, then in the general Spring framework, a more convenient and simple way is needed to support the cache.
SpringCache itself is an abstract implementation of a caching system, and there is no specific caching capability. To use SpringCache, you need to cooperate with a specific caching implementation to complete.
- Cache interface is the component specification definition of cache, including various operation collections of cache;
- Spring provides various xxxCache implementations under Cache interface; such as RedisCache, EhCacheCache , ConcurrentMapCache, etc.;
Two, important annotations, parameters
Name | Explanation |
---|---|
Cache | Cache interface, define cache operation. Implementations include: RedisCache, EhCacheCache, ConcurrentMapCache, etc. |
CacheManager | Cache manager, manage various cache (cache) components |
@Cacheable | Mainly for method configuration, which can be cached according to method request parameters | @CacheEvict | Empty the cache |
@CachePut | Guarantee The method is called and the result is hoped to be cached. The difference with @Cacheable is whether the method is called every time, which is often used to update |
@EnableCaching | Enable annotation-based caching |
keyGenerator | Key generation strategy when caching data |
serialize | Value serialization strategy when caching data |
@CacheConfig | Unified configuration of cache annotations of this class |
@Cacheable/@CachePut/@CacheEvict Main parameters
Name | Explanation | ||
---|---|---|---|
value | The name of the cache, defined in the spring configuration file, must specify at least one such as: @Cacheable(value=”mycache”) or @Cacheable(value={”cache1”,”cache2”} | ||
key | The cached key can be empty. If you specify to write according to SpEL expression, if not specified, all parameters of the method will be followed by default For example: @Cacheable(value=”testcache”,key=”#id”) | ||
condition | Cache conditions , Can be empty, written in SpEL, return true or false, only true will cache/clear cache. For example: @Cacheable(value=”testcache”,condition= ”#UserName.length()>2”) | ||
unless | Negative caching. When the condition result is TRUE, it will not be cached. @Cacheable(value=”testcache”,unless=”#userName.length()>2”) | ||
allEntries (@CacheEvict ) | Whether to clear all cache contents, the default is false, if specified as true, all caches will be cleared immediately after the method is called. For example: @CachEvict(value=”testcache”,allEntries=true) | ||
beforeInvocation (@CacheEvict) | Whether to clear before the method is executed, the default is false, if specified as true, when the method is not executed yet Just clear the cache. By default, if the method execution throws an exception, the cache will not be cleared. For example: @CachEvict(value=”testcache”, beforeInvocation=true) |
Name | Location | Description | Example |
---|---|---|---|
methodName | root object | The name of the currently called method | #root .methodname |
method | root object | The currently called method | #root.method.name |
target | root object | The currently called target object instance | #root.target |
targetClass | root object | The class of the target object currently being called | #root.targetClass |
args | root object | The parameter list of the currently called method | #root.args[0] |
caches | root object | The cache list used by the current method call | #root.caches[0].name |
Argument Name | execution context | The parameters of the currently called method, such as findArtisan(Artisan artisan), can be passed #artsian. id get parameters | #artsian.id |
result | execution context | The return value after the method is executed (only when the judgment after the method is executed is valid, such as beforeInvocation=false of unless cacheEvict) | #result |
< h1 id="Four Actual Combat">Four Actual Combat
1. Import Dependency
org.springframework. boot spring-boot-starter-cache
2. Start the class to enable caching annotation @EnableCaching
/** * 1. Enable annotation-based caching @EnableCaching * 2. Just mark the caching annotation * @Cacheable * @ CacheEvict * @CachePut */@SpringBootApplication@EnableCaching //Enable caching public class CacheApplication{ public static void main(String[] args) {SpringApplication.run(CacheApplication.class, args); })
3. Cache@Cacheable
Run process:
@Cacheable
Before the method runs, go Query the Cache (cache component), get it according to the name specified by cacheNames/value, the first time you get the cache, if there is no Cache component, it will be created automatically.
Source code analysis:
public @interface Cacheable {// cacheNames/value: Specify the name of the cache component; return the method Which cache to put the result in is an array. You can specify multiple caches @AliasFor("cacheNames") String[] value() default {}; @AliasFor("value") String[] cacheNames() default {} ; // Key used to cache data; you can use it to specify. The default is to use the value of the method parameter String key() default ""; // key generator; you can specify the component id of the key generator yourself, key/keyGenerator: choose one of two; String keyGenerator() default ""; // Specify the cache manager; or cacheResolver specifies to obtain the resolver function to get the cache collection String cacheManager() default ""; String cacheResolver() default ""; // If the condition is met, cache, write SpEL: condition = "#a0>1 ": Cache is only performed when the value of the first parameter is greater than 1. String condition() default ""; // If the condition is met, no cache, write SpEL:unless = "#a0==2": If the first parameter is The value is 2, the result is not cached; String unless() default ""; // Whether to use asynchronous mode, whether to enable asynchronous mode boolean sync() default false;}
Exercise it:
@Cacheable(value = "emp" ,key = "targetClass + methodName +#p0")public Employee getEmp(Integer id){ System.out.println("Query "+id+"号Employee"); Employee emp = employeeMapper.getEmpById(id); return emp;}
Step on the pit:
1, attributes value/cacheNames
is required, it specifies the namespace where your cache is stored.
2, the attribute key
is the spEL expression used
Note
: step on the pit, if you put methodName
If you change to method
and run, you will get an error. Observe their return types. The reason is that methodName
is String
and methoh code> is
Method
.
Employee
The entity class must be serialized public class Employee implements Serializable
, otherwise it will report java.io.NotSerializableException
abnormal.
4. Update @CachePut
@CachePut
not only calls the method, but also updates the cache data; updates the cache synchronously. Simply put, the user modifies the data and updates the cached data synchronously.
Source code analysis: (Take a look, the accident is the same as @Cacheable, don’t explain too much, dog head body guard~~~)
public @interface CachePut {@AliasFor("cacheNames") String[] value() default {}; @AliasFor("value") String[] cacheNames() default {}; String key() default "" ; String keyGenerator() default ""; String cacheManager() default ""; String cacheResolver() default ""; String condition() default ""; String unless() default "";}
< strong>Exercise:
Note
The value/cahceNames
and key
of the annotation must be updated The cache is the same as @Cacheable
.
@CachePut(value = "emp" ,key = "#employee.id")public Employee updateEmp(Employee employee){ System.out.println("updateEmp:"+employee ); employeeMapper.updateEmp(employee); return employee;}
5. Clear @CacheEvict
@CachEvict
The role of Mainly for method configuration, the cache can be cleared according to certain conditions.
Source code analysis:
public @interface CacheEvict {// Same as above Same as above @AliasFor("cacheNames") String[] value () default {}; @AliasFor("value") String[] cacheNames() default {}; String key() default ""; String keyGenerator() default ""; String cacheManager() default ""; String cacheResolver( ) default ""; String condition() default ""; // Specify to clear all data in this cache, example: @CachEvict(value=”emp”,allEntries=true) boolean allEntries() default false; /* * Example : @CachEvict(value=”emp”, beforeInvocation=true) * Indicates that the cache clear operation is executed before the method runs, regardless of whether the method is abnormal or not, the cache is cleared * * Example: @CachEvict(value=”emp”, beforeInvocation= false)(default) * Whether the cache clearing is performed before the method, the default means that the cache clearing operation is performed after the method is executed; if an exception occurs, the cache will not be cleared*/ boolean beforeInvocation() default false;)
< p>Exercise:
//Clear all caches after the method is called @CacheEvict(value="accountCache", allEntries=true)public void deleteEmp() {employeeMapper.deleteAll();}
6.Combination@Caching
Sometimes We may combine multiple Cache annotations. At this time, @Caching needs to combine multiple annotation tags.
Source code analysis:
public @interface Caching {// Used to specify multiple cache setting operations Cacheable[] cacheable() default {}; // Used to specify multiple cache update operations CachePut[] put() default {}; // Used to specify multiple cache invalidation operations CacheEvict[] evict() default {};}
< p>Practice it
// @Caching Define 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);}
7. Global Configuration@CacheConfig
When we need to cache more places The more you come, you can use the @CacheConfig(cacheNames = {"emp"})
annotation to uniformly specify the value of value
, then you can omit value
, if you still write value
in your method, then the value
value of the method still prevails.
Source code analysis:
public @interface Caching {// Used to specify multiple cache setting operations Cacheable[] cacheable() default {}; // Used to specify multiple cache update operations CachePut[] put() default {}; // Used to specify multiple cache invalidation operations CacheEvict[] evict() default {};}
< p>Practice it:
@CacheConfig(cacheNames = {"emp"}, /*keyGenerator = "cacheKeyGenerator"*/)public class EmployeeServiceImpl implements EmployeeService {@Override @Cacheable(/*value ='emp'*/ key = "targetClass + methodName +#p0") public Employee getEmp(Integer id){ Employee emp = employeeMapper.getEmpById(id); return emp; }}< /pre>8. Primary key generation strategy keyGenerator
Exercise it:
Create CacheConfig configuration class< /p>
@Configurationpublic class CacheConfig {/** * Generate cache primary key strategy (method name + parameters) * * @return KeyGenerator */ @Bean("cacheKeyGenerator") public KeyGenerator keyGenerator() { return (target, method, params) -> (method.getName() + "[" + Arrays.asList(params) + "]"); }}You can specify the generation strategy in
@CacheConfig
, also You can specify the key generation strategy in@Cacheable/@CachePut/@CacheEvict
@CacheConfig(cacheNames = {"emp"}, keyGenerator = "cacheKeyGenerator") public class EmployeeServiceImpl implements EmployeeService {@Override @Cacheable(/*value ='emp',keyGenerator = "cacheKeyGenerator"*/) public Employee getEmp(Integer id){ Employee emp = employeeMapper.getEmpById(id); return emp; }}WordPress database error: [Table 'yf99682.wp_s6mz6tyggq_comments' doesn't exist]
SELECT SQL_CALC_FOUND_ROWS wp_s6mz6tyggq_comments.comment_ID FROM wp_s6mz6tyggq_comments WHERE ( comment_approved = '1' ) AND comment_post_ID = 4744 ORDER BY wp_s6mz6tyggq_comments.comment_date_gmt ASC, wp_s6mz6tyggq_comments.comment_ID ASC