Use spring's interceptor to customize the cache implementation example code
- 2021-01-25 07:28:40
- OfStack
This paper mainly studies the implementation of custom cache using spring interceptor. The specific implementation code is shown below.
Memcached is a high-performance distributed memory object caching system for dynamic Web applications to reduce database load. It improves the speed of dynamic, database-driven Web sites by caching data and objects in memory to reduce the number of database reads. This article uses Memcached instances and spring interceptors to implement a custom implementation of caching. Using interceptors to read the generation strategy for key values taken from the defined cache tags.
Custom Cacheable
package com.jeex.sci;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
String namespace();
String key() default "";
int[] keyArgs() default {
}
;
String[] keyProperties() default {
}
;
String keyGenerator() default "";
int expires() default 1800;
}
Custom CacheEvict
package com.jeex.sci;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {
String namespace();
String key() default "";
int[] keyArgs() default {
}
;
String[] keyProperties() default {
}
;
String keyGenerator() default "";
}
spring: MethodInterceptor public Object invoke(MethodInvocation invocation) throws Throwable (MethodInvocation invocation) spring: MethodInterceptor public Object invoke(MethodInvocation invocation) Throwable
public Object invoke(MethodInvocation invoction) throws Throwable {
Method method = invoction.getMethod();
Cacheable c = method.getAnnotation(Cacheable.class);
if (c != null) {
return handleCacheable(invoction, method, c);
}
CacheEvict ce = method.getAnnotation(CacheEvict.class);
if (ce != null) {
return handleCacheEvict(invoction, ce);
}
return invoction.proceed();
}
Process cacheable tags
private Object handleCacheable(MethodInvocation invoction, Method method,
Cacheable c) throws Throwable {
String key = getKey(invoction, KeyInfo.fromCacheable(c));
if (key.equals("")) {
if (log.isDebugEnabled()){
log.warn("Empty cache key, the method is " + method);
}
return invoction.proceed();
}
long nsTag = (long) memcachedGet(c.namespace());
if (nsTag == null) {
nsTag = long.valueOf(System.currentTimeMillis());
memcachedSet(c.namespace(), 24*3600, long.valueOf(nsTag));
}
key = makeMemcachedKey(c.namespace(), nsTag, key);
Object o = null;
o = memcachedGet(key);
if (o != null) {
if (log.isDebugEnabled()) {
log.debug("CACHE HIT: Cache Key = " + key);
}
} else {
if (log.isDebugEnabled()) {
log.debug("CACHE MISS: Cache Key = " + key);
}
o = invoction.proceed();
memcachedSet(key, c.expires(), o);
}
return o;
}
Process cacheEvit labels
private Object handleCacheEvict(MethodInvocation invoction,
CacheEvict ce) throws Throwable {
String key = getKey(invoction, KeyInfo.fromCacheEvict(ce));
if (key.equals("")) {
if (log.isDebugEnabled()) {
log.debug("Evicting " + ce.namespace());
}
memcachedDelete(ce.namespace());
} else {
Long nsTag = (Long) memcachedGet(ce.namespace());
if (nsTag != null) {
key = makeMemcachedKey(ce.namespace(), nsTag, key);
if (log.isDebugEnabled()) {
log.debug("Evicting " + key);
}
memcachedDelete(key);
}
}
return invoction.proceed();
}
key is generated according to the parameters
// Generate parameters using the parameters of the intercepted method
private String getKeyWithArgs(Object[] args, int[] argIndex) {
StringBuilder key = new StringBuilder();
boolean first = true;
for (int index: argIndex) {
if (index < 0 || index >= args.length) {
throw new IllegalArgumentException("Index out of bound");
}
if (!first) {
key.append(':');
} else {
first = false;
}
key = key.append(args[index]);
}
return key.toString();
}
key is generated based on the properties
private String getKeyWithProperties(Object o, String props[])
throws Exception {
StringBuilder key = new StringBuilder();
boolean first = true;
for (String prop: props) {
// the bean To get the name of the method
String methodName = "get"
+ prop.substring(0, 1).toUpperCase()
+ prop.substring(1);
Method m = o.getClass().getMethod(methodName);
Object r = m.invoke(o, (Object[]) null);
if (!first) {
key.append(':');
} else {
first = false;
}
key = key.append(r);
}
return key.toString();
}
key is generated using a custom generator
// Generate using a generator key
private String getKeyWithGenerator(MethodInvocation invoction, String keyGenerator)
throws Exception {
Class<?> ckg = Class.forName(keyGenerator);
CacheKeyGenerator ikg = (CacheKeyGenerator)ckg.newInstance();
return ikg.generate(invoction.getArguments());
}
Helper class that holds key information
private static class KeyInfo {
String key;
int[] keyArgs;
String keyProperties[];
String keyGenerator;
static KeyInfo fromCacheable(Cacheable c) {
KeyInfo ki = new KeyInfo();
ki.key = c.key();
ki.keyArgs = c.keyArgs();
ki.keyGenerator = c.keyGenerator();
ki.keyProperties = c.keyProperties();
return ki;
}
static KeyInfo fromCacheEvict(CacheEvict ce) {
KeyInfo ki = new KeyInfo();
ki.key = ce.key();
ki.keyArgs = ce.keyArgs();
ki.keyGenerator = ce.keyGenerator();
ki.keyProperties = ce.keyProperties();
return ki;
}
String key() {
return key;
}
int[] keyArgs() {
return keyArgs;
}
String[] keyProperties() {
return keyProperties;
}
String keyGenerator() {
return keyGenerator;
}
}
Parameter setting
// Use parameter Settings key
@Cacheable(namespace="BlackList", keyArgs={0, 1})
public int anotherMethond(int a, int b) {
return 100;
}
The test class:
package com.jeex.sci;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {
String namespace();
String key() default "";
int[] keyArgs() default {
}
;
String[] keyProperties() default {
}
;
String keyGenerator() default "";
}
0
conclusion
This article is about the use of spring interceptor custom cache implementation example code is all content, I hope to help you. Interested friends can continue to refer to the site of other related topics, if there are shortcomings, welcome to leave a message to point out. Thank you for your support!