自从spring3.1之后,spring引入了抽象缓存,可以通过在方法上添加@Cacheable等标签对方法返回的数据进行缓存。但是它到底是怎么实现的呢,我们通过一个例子来看一下。首先我们定义一个@MyCacheable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package caching.springaop;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* 使用@MyCacheable注解方法
*/
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.METHOD)
public @interface MyCacheable{
}
|
然后定义处理MyCacheable的切面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
package caching.springaop;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* 处理MyCacheable方法的切面
*/
@Aspect
public class CacheAspect {
private Logger logger = Logger.getLogger(CacheAspect. class );
private Map<String, Object> cache;
public CacheAspect() {
cache = new HashMap<String, Object>();
}
/**
* 所有标注了@Cacheable标签的方法切入点
*/
@Pointcut ( "execution(@MyCacheable * *.*(..))" )
@SuppressWarnings ( "unused" )
private void cache() {
}
@Around ( "cache()" )
public Object aroundCachedMethods(ProceedingJoinPoint thisJoinPoint)
throws Throwable {
logger.debug( "Execution of Cacheable method catched" );
//产生缓存数据的key值,像是这个样子caching.aspectj.Calculator.sum(Integer=1;Integer=2;)
StringBuilder keyBuff = new StringBuilder();
//增加类的名字
keyBuff.append(thisJoinPoint.getTarget().getClass().getName());
//加上方法的名字
keyBuff.append( "." ).append(thisJoinPoint.getSignature().getName());
keyBuff.append( "(" );
//循环出cacheable方法的参数
for ( final Object arg : thisJoinPoint.getArgs()) {
//增加参数的类型和值
keyBuff.append(arg.getClass().getSimpleName() + "=" + arg + ";" );
}
keyBuff.append( ")" );
String key = keyBuff.toString();
logger.debug( "Key = " + key);
Object result = cache.get(key);
if (result == null ) {
logger.debug( "Result not yet cached. Must be calculated..." );
result = thisJoinPoint.proceed();
logger.info( "Storing calculated value '" + result + "' to cache" );
cache.put(key, result);
} else {
logger.debug( "Result '" + result + "' was found in cache" );
return result;
}
}
|
上述代码展示了如何处理MyCacheable自定义的标签,以及默认情况下产生key值的规则。最后生成的key值大概是这个样子:caching.aspectj.Calculator.sum(Integer=1;Integer=2;)
下边这段代码在方法上添加了MyCacheable标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package caching.springaop;
import org.apache.log4j.Logger;
public class Calculator {
private Logger logger = Logger.getLogger(Calculator. class );
@MyCacheable
public int sum( int a, int b) {
logger.info( "Calculating " + a + " + " + b);
try {
//假设这是代价非常高的计算
Thread.sleep( 3000 );
} catch (InterruptedException e) {
logger.error( "Something went wrong..." , e);
}
return a + b;
}
}
|
在方法上加了MyCacheable标签,当key值相同的情况下会直接在缓存中获取数据,如果没有相同的key值,则会重新计算,因为这里只是一个加和操作,耗时非常的短暂。我们在这里让其睡眠3秒钟。
我们在spring-config.xml配置如下:
1
2
3
4
5
6
7
8
9
10
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop = "http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
< aop:aspectj-autoproxy />
< bean class = "caching.springaop.CacheAspect" />
< bean id = "calc" class = "caching.springaop.Calculator" />
</ beans >
|
测试类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package caching.springaop;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 使用SpringAOP缓存的简单例子
* @author txxs
*/
public class App {
private static Logger logger = Logger.getLogger(App. class );
public static void main(String[] args) {
logger.debug( "Starting..." );
ApplicationContext ctx = new ClassPathXmlApplicationContext( "spring-config.xml" );
Calculator calc = (Calculator) ctx.getBean( "calc" );
//计算出来的结果将会被存储在cache
logger.info( "1 + 2 = " + calc.sum( 1 , 2 ));
//从缓存中获取结果
logger.info( "1 + 2 = " + calc.sum( 1 , 2 ));
logger.debug( "Finished!" );
}
}
|
我们看一下运行的结果:
从结果来看第一次直接计算结果,第二次从缓存中获取。
以上就是spring实现自定义缓存标签的全部内容,希望对大家的学习有所帮助