Java開發(fā)框架spring實(shí)現(xiàn)自定義緩存標(biāo)簽
自從spring3.1之后,spring引入了抽象緩存,可以通過(guò)在方法上添加@Cacheable等標(biāo)簽對(duì)方法返回的數(shù)據(jù)進(jìn)行緩存。但是它到底是怎么實(shí)現(xiàn)的呢,我們通過(guò)一個(gè)例子來(lái)看一下。首先我們定義一個(gè)@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{
}
然后定義處理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>();
}
/**
* 所有標(biāo)注了@Cacheable標(biāo)簽的方法切入點(diǎn)
*/
@Pointcut("execution(@MyCacheable * *.*(..))")
@SuppressWarnings("unused")
private void cache() {
}
@Around("cache()")
public Object aroundCachedMethods(ProceedingJoinPoint thisJoinPoint)
throws Throwable {
logger.debug("Execution of Cacheable method catched");
//產(chǎn)生緩存數(shù)據(jù)的key值,像是這個(gè)樣子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("(");
//循環(huán)出cacheable方法的參數(shù)
for (final Object arg : thisJoinPoint.getArgs()) {
//增加參數(shù)的類型和值
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自定義的標(biāo)簽,以及默認(rèn)情況下產(chǎn)生key值的規(guī)則。最后生成的key值大概是這個(gè)樣子:caching.aspectj.Calculator.sum(Integer=1;Integer=2;)
下邊這段代碼在方法上添加了MyCacheable標(biāo)簽
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 {
//假設(shè)這是代價(jià)非常高的計(jì)算
Thread.sleep(3000);
} catch (InterruptedException e) {
logger.error("Something went wrong...", e);
}
return a + b;
}
}
在方法上加了MyCacheable標(biāo)簽,當(dāng)key值相同的情況下會(huì)直接在緩存中獲取數(shù)據(jù),如果沒(méi)有相同的key值,則會(huì)重新計(jì)算,因?yàn)檫@里只是一個(gè)加和操作,耗時(shí)非常的短暫。我們?cè)谶@里讓其睡眠3秒鐘。
我們?cè)趕pring-config.xml配置如下:
<?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>
測(cè)試類:
package caching.springaop;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 使用SpringAOP緩存的簡(jiǎn)單例子
* @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");
//計(jì)算出來(lái)的結(jié)果將會(huì)被存儲(chǔ)在cache
logger.info("1 + 2 = " + calc.sum(1, 2));
//從緩存中獲取結(jié)果
logger.info("1 + 2 = " + calc.sum(1, 2));
logger.debug("Finished!");
}
}
我們看一下運(yùn)行的結(jié)果:

從結(jié)果來(lái)看第一次直接計(jì)算結(jié)果,第二次從緩存中獲取。
以上就是spring實(shí)現(xiàn)自定義緩存標(biāo)簽的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助
相關(guān)文章
Java注冊(cè)郵箱激活驗(yàn)證實(shí)現(xiàn)代碼
這篇文章主要介紹了Java注冊(cè)郵箱激活驗(yàn)證實(shí)現(xiàn)代碼,有需要的朋友可以參考一下2013-12-12
解決Mybatis?mappe同時(shí)傳遞?List?和其他參數(shù)報(bào)錯(cuò)的問(wèn)題
在使用MyBatis時(shí),如果需要傳遞多個(gè)參數(shù)到SQL中,可以遇到參數(shù)綁定問(wèn)題,解決方法包括使用@Param注解和修改mapper.xml配置,感興趣的朋友跟隨小編一起看看吧2024-09-09
Java中Map與對(duì)象之間互相轉(zhuǎn)換的幾種常用方式
在Java中將對(duì)象和Map相互轉(zhuǎn)換是常見的操作,可以通過(guò)不同的方式實(shí)現(xiàn)這種轉(zhuǎn)換,下面這篇文章主要給大家介紹了關(guān)于Java中Map與對(duì)象之間互相轉(zhuǎn)換的幾種常用方式,需要的朋友可以參考下2024-01-01
Spring Data Jpa 自動(dòng)生成表結(jié)構(gòu)的方法示例
這篇文章主要介紹了Spring Data Jpa 自動(dòng)生成表結(jié)構(gòu)的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Java如何接收XML格式參數(shù)并轉(zhuǎn)換為JSON
在 Java 應(yīng)用程序中,處理 XML 數(shù)據(jù)并將其轉(zhuǎn)換為 JSON 格式是很常見的任務(wù),這篇文章為大家整理了一下具體的實(shí)現(xiàn)方法,希望對(duì)大家有所幫助2025-03-03
springBoot?@Scheduled實(shí)現(xiàn)多個(gè)任務(wù)同時(shí)開始執(zhí)行
這篇文章主要介紹了springBoot?@Scheduled實(shí)現(xiàn)多個(gè)任務(wù)同時(shí)開始執(zhí)行,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

