[Spring Cache] II. Notes and attributes related to Spring Cache operation

Posted by locell on Thu, 03 Feb 2022 10:03:39 +0100

preface

In this chapter, learn about the Spring defined annotation @ Cacheable @CachePut @CacheEvict @Caching @CacheConfig and related properties

@Cacheable

/**
 * Cacheable Indicates that the caching behavior is enabled. If it is on the annotation class, it means that all methods are cached
 * Cache keys are generated based on parameters. You can also specify a SpEL expression or customize the KeyGenerator
 * If the cached result is not obtained, the result of the method execution is cached. If the return value type of the method is
 * 		Optional,The cached value will be the actual value
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {

	@AliasFor("cacheNames")
	String[] value() default {};

	// Target cache name for matching cache
	@AliasFor("value")
	String[] cacheNames() default {};

	/**
	 * Support the SpEL expression to specify the key. If it is empty by default, it will be generated based on the keyGenerator,
	 * 		If keyGenerator is not specified, it is generated based on parameters
	 * SpEL The context of provides the following parameters
	 * 		#root.method: Target method
	 * 		#root.target: Target object
	 * 	    #root.caches: Target Cache
	 * 	    #root.methodName: Method name abbreviation
	 * 	    #root.targetClass: Target Class
	 * 	    The target parameters are obtained: #root args[1] || #p1 || #a1
	 */
	String key() default "";

	// Customize the beanName of KeyGenerator, which is mutually exclusive with the key attribute
	String keyGenerator() default "";

	// If cacheResolver is not specified, it is obtained based on the beanName of this CacheManager
	// With cacheResolver 	 Attribute mutual exclusion
	String cacheManager() default "";

	// beanName of custom CacheResolver
	String cacheResolver() default "";

	// The condition expression based on spiel specifies the condition triggered by the cache. It is empty by default, that is, it is triggered unconditionally
	String condition() default "";

	/**
	 * Cache condition judgment of method execution results based on spiel
	 * The default is empty, which means that the results are unconditionally cached
	 * It can also be accessed based on the previous context
	 * 		#result: Method. For the Optional return value, it gets the actual value
	 */
	String unless() default "";

	/**
	 * Indicates whether the target method supports synchronous operation in a concurrent environment. When enabled, it is subject to the following restrictions:
	 * 1)The unless attribute is not supported
	 * 2)Only one cache can be specified by the cacheNames property
	 * 3)Other operations at the same time or merging of multiple cacheables are not supported
	 * However, whether cache synchronization is supported or not actually depends on the implementation of the underlying vendor
	 */
	boolean sync() default false;

}
  • If it is marked on the class, all methods are identified. If it is marked on the method, the target method is identified and the cache operation is enabled
  • The cache operation will get the target method from the target cache before executing the target method. The target method will be executed only if it cannot be obtained, and then the result will be cached
  • Provides a number of properties:
    • Value & cachenames: the name of the Cache used to match the Cache target
    • Key & keyGenerator: used to parse the cacheKey. The key attribute allows you to specify a SpEL expression to calculate the cacheKey. If it is not specified, it will be generated based on the customized keyGenerator. If it is not specified, it will be generated based on parameters. It is not difficult to understand that key and keyGenerator are mutually exclusive
    • cacheManager & cacheResolver: it is also a pair of mutually exclusive attributes. When cacheResolver is not provided, it will try to resolve the corresponding cacheResolver based on cacheManager
    • Condition & unless: condition expression calculated based on spiel. The difference is that the latter determines whether to cache based on the return value of the method, so its Expression Context contains #result variable additionally
    • sync: indicates whether the synchronization operation is supported, which is finally supported by the specific Provider

@CachePut

/**
 * Cache all or specified methods on the target class
 * Unlike @ Cacheable, it is triggered as long as the condition & unless is met,
 * 		Instead of checking the target Cache first
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
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 "";

}
  • Similar to @ Cacheable, this annotation indicates that the corresponding method starts the cache insertion operation. The difference is that this operation does not judge whether the cache exists, that is, it only determines whether the cache exists based on condition & unless
  • Its properties are basically understood. It does not provide sync operation, that is, it does not support synchronization operation

@CacheEvict

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
// This annotation indicates that all or specified methods on the class will perform culling on the target cache
public @interface CacheEvict {

	@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 "";

	/**
	 * Whether to remove all caches of the target Cache. Default false means to clear only the specified key
	 * 		When it is true, the key attribute cannot be specified
	 */
	boolean allEntries() default false;

	/**
	 * Whether the cache culling operation occurs before the method is executed
	 * The default false indicates that the culling operation will not be performed until the target method is successfully executed
	 * true It means to eliminate it first, regardless of the execution result of the method
	 */
	boolean beforeInvocation() default false;

}
  • This annotation enables the cache culling operation of the target method
  • Based on the previously understood attributes, it expands:
    • allEntries: indicates whether to empty the target cache. The default is false. Only the specified cache is removed. When this attribute is true, the key attribute is not allowed to be specified
    • beforeInvocation: indicates whether the culling operation is performed before the target method is executed. The default is false, that is, the removal is performed after the target method is executed successfully. Otherwise, the removal is performed before the target method is executed (regardless of whether the method is executed successfully)

@Caching

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
// This annotation is mainly for a scenario where a method supports a set of similar (different) cache operations
public @interface Caching {

	Cacheable[] cacheable() default {};

	CachePut[] put() default {};

	CacheEvict[] evict() default {};

}

This annotation is used to identify a series of caching behaviors

@CacheConfig

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// Used to provide default cache configuration at the class level
public @interface CacheConfig {

	String[] cacheNames() default {};

	String keyGenerator() default "";

	String cacheManager() default "";

	String cacheResolver() default "";

}
  • This annotation is used on the class to provide a default configuration for all cache operations under it
  • It mainly provides the attribute cacheNames keyGenerator cacheManager cacheResolver

KeyGenerator

@FunctionalInterface
public interface KeyGenerator {

	// Generate key based on target method parameters
	Object generate(Object target, Method method, Object... params);

}
  • The keygenerator specified in the above annotation is the beanName of the corresponding instance of keygenerator
  • It generates the specified key for the target cache operation based on target method parameters
  • The built-in implementation SimpleKeyGenerator provided by Spring Cache generates the corresponding SimpleKey based on parameters

CacheResolver

@FunctionalInterface
public interface CacheResolver {

	// Obtain the corresponding Cache collection based on CacheOperationInvocationContext
	Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);

}

Used to resolve the Cache collection corresponding to the target Cache operation

AbstractCacheResolver

public abstract class AbstractCacheResolver implements CacheResolver, InitializingBean {

	@Nullable
	private CacheManager cacheManager;

	// ...

	@Override
	public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {

		// Obtain cacheNames based on CacheOperationInvocationContext
		Collection<String> cacheNames = getCacheNames(context);
		if (cacheNames == null) {
			return Collections.emptyList();
		}

		// Obtain the corresponding Cache collection from the CacheManager based on cacheNames
		Collection<Cache> result = new ArrayList<>(cacheNames.size());
		for (String cacheName : cacheNames) {
			Cache cache = getCacheManager().getCache(cacheName);
			result.add(cache);
		}
		return result;
	}

	// Subclass implementation, and obtain the corresponding cacheNames based on CacheOperationInvocationContext
	@Nullable
	protected abstract Collection<String> getCacheNames(CacheOperationInvocationContext<?> context);

}

Abstract implementation of CacheResolver:

  • A CacheManager needs to be specified
  • getCacheNames gets the corresponding cacheNames based on CacheOperationInvocationContext
  • Based on the above cacheNames, the CacheManager obtains the corresponding Cache set

SimpleCacheResolver

public class SimpleCacheResolver extends AbstractCacheResolver {

	// ...

	// Get from CacheOperation
	@Override
	protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
		return context.getOperation().getCacheNames();
	}

	// ...

}
  • The built-in implementation provided by Spring Cache, in which the getCacheNames method obtains cacheNames from the corresponding CacheOperation
  • CacheOperationInvocationContext refers to the context information of the execution of the entire cache operation method, which will be understood in detail in subsequent articles

summary

The contents of this chapter are all defined annotations and auxiliary attribute classes, so no specific example demo is given, but these classes are interspersed in the subsequent details of Spring Cache

Previous article: [Spring Cache] CacheManager

Next: [Spring Cache] three CacheOperationInvocationContext CacheOperationExpressionEvaluator

Topics: Java Spring Cache