基于注解的SpringAOP Redis缓存技术

这篇博文主要介绍如何使用SpringAOP + Redis +注解的方式实现缓存的开发。

一、术语说明

1、SpringAOP

AOP(Aspect Oriented Programming),也就是面向方面编程的技术。AOP基于IOC基础,是对OOP的有益补充。SpringAOP的可配置式,使得代码几乎没有耦合侵入。

2、Redis

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis已经成为NOSQL的典范。

3、注解

采用注解的方式,使得代码没有侵入,动态可配置式。

二、思路

在数据没有变化的时候,采用本地数据,如果数据有了变化,那么将从数据库获取最新数据,并缓存到本地(可以通过各种方式的缓存,比如HTML5可以采用localStorge),参照下图
基于注解的SpringAOP Redis缓存技术_第1张图片

三、主要代码片段

1、pom.xml,用来集成Spring和Redis



	org.springframework.data
	spring-data-redis
	1.6.1.RELEASE


	redis.clients
	jedis
	2.7.3


2、Spring-dispather

3、SpringContent,配置Redis连接




      
      
      




      
      
      
      
      


      
      
          
      
      
          
      





      



 
       
 
 

4、Redis.properties

#redis中心
#绑定的主机地址
redis.host=127.0.0.1
#指定Redis监听端口,默认端口为6379
redis.port=6379 
#授权密码(本例子没有使用)
redis.password=
#最大空闲数:空闲链接数大于maxIdle时,将进行回收
redis.maxIdle=100  
#最大连接数:能够同时建立的“最大链接个数”
redis.maxActive=300  
#最大等待时间:单位ms
redis.maxWait=1000   
#使用连接时,检测连接是否成功 
redis.testOnBorrow=true 
#当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
redis.timeout=10000 

5、自定义注解

(1)生成缓存版本PutCache.java
/**
 * 自定义注解,在插入、更新或者删除的时候更新对应的版本
 * @author Chenth
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface PutCache {
	String name() default "";
	String value() default "";
}
(2)获取缓存版本GetCache.java
/**
 * 自定义注解,对于查询使用缓存的方法加入该注解
 * @author Chenth
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface GetCache {
	String name() default "";
	String value() default "";
}

6、加入AOP

(1)、GetCache对应的切面
@Aspect
public class GetCacheAOP {
	
	private RedisTemplate redisTemplate;

	ThreadLocal time=new ThreadLocal();
	ThreadLocal tag=new ThreadLocal();
	
	@Pointcut("@annotation(com.ninesky.classtao.springaop.annotation.GetCache)")
	public void getCache(){
		System.out.println("我是一个切入点");
	}
	
	/**
	 * 在所有标注@getCache的地方切入
	 * @param joinPoint
	 */
	@Before("getCache()")
	public void beforeExec(JoinPoint joinPoint){
		MethodSignature ms=(MethodSignature) joinPoint.getSignature();
		Method method=ms.getMethod();
		String ActionName = method.getAnnotation(GetCache.class).name();
		String fieldList = method.getAnnotation(GetCache.class).value();
		for (String field:fieldList.split(",")) 
		{
			if ("school_id".equals(field))
				ActionName+="#"+ActionUtil.getSchoolID();
			else if ("user_id".equals(field))
				ActionName+="#"+ActionUtil.getUserID();
			else if ("user_type".equals(field))
				ActionName+="#"+ActionUtil.getUserType();
			else ActionName+="#"+ActionUtil.getParameter(field);
		}
		ValueOperations operations =redisTemplate.opsForValue();
		ActionUtil.setCache(true);
		//如果是第一次取值.则将版本存放到redis数据库
		if (operations.get(ActionName)==null)  {
			operations.increment(ActionName, 1);
			return;
		}
		if (operations.get(ActionName).equals(ActionUtil.getParameter("cache_version"))) 
			throw new CacheException("数据没有更新,可以采用本地数据!");
		ActionUtil.setCache_version(operations.get(ActionName)+"");
	}
	
	public void setRedisTemplate(
			RedisTemplate redisTemplate) {
		this.redisTemplate = redisTemplate;
	}
}
(2)、PutCache对应的切面
@Aspect
public class PutCacheAOP {
	
	private RedisTemplate redisTemplate;

	ThreadLocal time=new ThreadLocal();
	ThreadLocal tag=new ThreadLocal();
	
	@Pointcut("@annotation(com.ninesky.classtao.springaop.annotation.PutCache)")
	public void PutCache(){
		System.out.println("我是一个切入点");
	}
	
	/**
	 * 在所有标注@PutCache的地方切入
	 * @param joinPoint
	 */
	@After("PutCache()")
	public void AfterExec(JoinPoint joinPoint){
		MethodSignature ms=(MethodSignature) joinPoint.getSignature();
		Method method=ms.getMethod();
		String ActionName = method.getAnnotation(PutCache.class).name();
		String fieldList = method.getAnnotation(PutCache.class).value();
		for (String field:fieldList.split(",")) 
			ActionName+="#"+ActionUtil.getParameter(field);
		ValueOperations operations =redisTemplate.opsForValue();
		operations.increment(ActionName, 1);
	}
	
	
	public void setRedisTemplate(
			RedisTemplate redisTemplate) {
		this.redisTemplate = redisTemplate;
	}
}

7、最后,在Controller中添加注解

/**
 * 添加消息(校园风采、党建)
 * @param request
 */
@PutCache(name="newsList",value="school_id,news_code")
@RequestMapping(value="/addNews")
public @ResponseBody Object addNews(HttpServletRequest request){
	NewsVO vo = BeanUtil.formatToBean(NewsVO.class);
	newsService.addNews(vo);
	newsService.addInformation(vo);
	return ResponseUtils.sendSuccess(vo);
}

/**
 * 获取消息列表(Web)
 * @param request
 * @return
 */
@GetCache(name="newsList",value="school_id,news_code")
@RequestMapping(value="/getNewsListForWeb")
public @ResponseBody Object getNewsList(HttpServletRequest request){
	NewsVO vo = BeanUtil.formatToBean(NewsVO.class);
	if(IntegerUtil.isEmpty(vo.getSchool_id()))
		vo.setSchool_id(ActionUtil.getSchoolID());
	List list = newsService.getNewsList(vo);
	return ResponseUtils.sendSuccess(list);
}

8、成功了,该方法降低了应用的数据库请求次数和时间消耗,提高了查询效率




你可能感兴趣的:(基于注解的SpringAOP Redis缓存技术)