In-depth Spring Cache use and integration (attachment analysis)

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

td>

< tr class="even">

td>

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

< tr class="header">

3. SpEL context data

Spring Cache provides some SpEL context data for us to use. The following table is directly taken from Spring official documents:

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 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; }} 

Leave a Comment

Your email address will not be published.