天天看點

spring-aop + memcached 的簡單實作

一般情況下,java程式取一條資料是直接從資料庫中去取,當資料庫達到一定的連接配接數時,就會處于排隊等待狀态, 某些在一定時間内不會發生變化的資料,完全沒必要每次都從資料庫中去取, 使用spring-aop + memcached 技術,取資料時,先從緩存中去取,緩存中如果存在,直接傳回結果,無需通路資料庫;如果緩存中不存在,再通路資料庫,并把這條資料儲存到緩存中,當程式下次再通路時,就可以取到緩存中的值了。這樣不但可以大大減少通路資料庫的次數(減輕資料的負擔),而且可以提高程式的運作效率,因為memecached 是采用key - value 方法存取資料的。

使用memcached時特别需要注意的是: 1.當某條資料發生變化時,一定要更新cache中的這條記錄; 2.設定key時一定要唯一, 一般是通過prefix + uuid 保證唯一,prefix一般使用資料庫的表名

下面來介紹一下spring-aop + memcached 技術的簡單實作:

spring-aop + memcached 的簡單實作

1.定義注解類 @Cache

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {

	/**
	 * key的字首
	 * @return
	 */
	String prefix();
	
	/**
	 * 指定哪個參數值做Key,與cacheKey兩者選一,如果都有輸入,預設使用indexKey
	 * @return
	 */
	int indexKey() default 0;
	/**
	 * 緩存有效期 1000*60*60*2=2小時
	 * @return
	 */
	long expiration() default 1000 * 60 * 60 * 2;
}
           

2.定義切入點類 CachePoint,這個類一定要與上面的注解類在同一包目錄下

@Component
@Aspect
public class CachePoint {
    
	@Autowired
	private CacheService cacheService;
	
	/**
	 * @Pointcut("@annotation(Cache)") 表示定義切入點所有帶有@Cache注解的方法
	 */
	@Pointcut("@annotation(Cache)")
    public void queryCache(){
		System.out.println("此輸出将不會執行...");
    }

    @Around("queryCache()")
    public Object getByCache(ProceedingJoinPoint pjp) throws Throwable {
    	// 1.查詢緩存的值
    	Object obj  = cacheService.getKey("test_1000123456");
    	// 2.如果緩存中不存在,則查詢mysql資料庫
    	if (null==obj) {
    		obj = pjp.proceed();
    		// 3.将obj的值寫入緩存
    		cacheService.setKey("test_1000123456", obj);
    	}
    	return obj;
    }
 
}
           

3.編寫memcached 的業務類

@Component("cacheService")
public class CacheService {
	/**
	 * 讀取緩存的方法
	 * @param key
	 * @return
	 */
	public Object getKey(String key) {
		System.out.println("query from memcached");
		return null;
	}
	/**
	 * 寫入緩存的方法
	 * @param key
	 * @param obj
	 */
	public void setKey(String key, Object obj) {
		
	}
	/**
	 * 删除緩存的方法
	 * @param key
	 */
	public void delete(String key) {
		
	}

}
           

4.Dao 的實作層添加注解

@Component("testDao")
public class TestDaoImpl implements TestDao {
	
	/**
	 * 此處将使用 prefix + indexKey 作為緩存的key,即 test_ + uuid
	 */
	@Cache(indexKey=1, prefix="test_")
	@Override
	public String query(String uuid) {
		System.out.println("query from mysql");
		return "caoxiaobo";
	}
}
           

配置檔案spring-aop.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                        http://www.springframework.org/schema/aop 
                        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
                        http://www.springframework.org/schema/context  
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd  
                        http://www.springframework.org/schema/mvc  
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
    <!-- 自動掃描 -->
    <context:component-scan base-package="com.spring.*" />
    <!-- 開啟注入注解掃描  -->
    <context:annotation-config/>
    <aop:aspectj-autoproxy/>
</bea
           

測試:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-aop.xml" })
public class SprintAopAndCacheTest {
	
	@Autowired
	TestService testService;
	
    @Test
    public void test() {
    	String name = testService.query("1000123456");
        System.out.println(name);
    }
}