Since spring 3.1, spring has introduced abstract caching, which can cache the data returned by the method by adding tags such as @Cacheable to the method. But how is it implemented? Let’s take a look at an example. First we define a @MyCacheable
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{ }
and then define the aspect that handles MyCacheable
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; } }
The above code shows how to handle MyCacheable custom tags and the rules for generating key values by default. The final generated key value probably looks like this: caching.aspectj.Calculator.sum(Integer=1;Integer=2;)
The code below adds the MyCacheable tag to the method
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; } }
The MyCacheable tag is added to the method. When the key values are the same, the data will be obtained directly from the cache. If there is no same key value, it will be recalculated because it is just an addition. And the operation takes very little time. We let it sleep for 3 seconds here.
We configure spring-config.xml as follows:
<?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>
Test class:
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!"); } }
Let’s take a look at the results of the operation:
From the results, the first time the result is calculated directly, and the second time it is obtained from the cache.
The above is all the content of spring's implementation of custom cache tags. I hope it will be helpful to everyone's study.
For more articles related to Java development framework spring's implementation of custom cache tags, please pay attention to the PHP Chinese website !