码迷,mamicode.com
首页 > 其他好文 > 详细

maven 使用AOP 增加 缓存逻辑 Redis

时间:2015-05-05 20:01:49      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:

    项目搭建过程中,缓存逻辑在某种程度上,是必不可少了,本文在之前的Maven多模块项目的基础上,在service层使用AOP增加了redis缓存逻辑。

    具体代码已上传git :  http://git.oschina.net/alexgaoyh/MutiModule-parent

    具体效果,可以直接执行junit单元测试即可,文章并不针对这些测试进行截图操作了。

    下面备注上一些需要注意的事项:

    

<spring-data-redis>1.4.1.RELEASE</spring-data-redis>
<redis.clients.jedis>2.6.0</redis.clients.jedis>
<org.codehaus.jackson>1.9.13</org.codehaus.jackson>
<dependency>  
		        <groupId>org.springframework.data</groupId>  
		        <artifactId>spring-data-redis</artifactId>  
		        <version>${spring-data-redis}</version>  
		    </dependency>
		    <dependency>  
		        <groupId>redis.clients</groupId>  
		        <artifactId>jedis</artifactId>  
		        <version>${redis.clients.jedis}</version>  
		    </dependency>
<dependency>
				<groupId>org.codehaus.jackson</groupId>
				<artifactId>jackson-core-asl</artifactId>
				<version>${org.codehaus.jackson}</version>
			</dependency>
			<dependency>
				<groupId>org.codehaus.jackson</groupId>
				<artifactId>jackson-mapper-asl</artifactId>
				<version>${org.codehaus.jackson}</version>
			</dependency>


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

	<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="minIdle" value="1" />
		<property name="maxIdle" value="5" />
		<property name="maxTotal" value="5" />
		<property name="maxWaitMillis" value="10001" />
		<property name="testOnBorrow" value="false" />
	</bean>

	<bean id="jedisConnFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<property name="hostName" value="192.168.0.135" />
		<property name="port" value="6379" />
		<property name="password" value="" />
		<property name="usePool" value="true" />
		<property name="poolConfig" ref="poolConfig" />
	</bean>

	<!-- redis template definition -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="connectionFactory" ref="jedisConnFactory" />
		<property name="keySerializer">
			<bean
				class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="valueSerializer">
			<bean
				class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
		</property>
		<property name="hashKeySerializer">
			<bean
				class="org.springframework.data.redis.serializer.StringRedisSerializer" />
		</property>
		<property name="hashValueSerializer">
			<bean
				class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
		</property>
	</bean>

</beans>



<!-- redis 缓存控制层 begin-->
	
	<bean id="redisHandler" class="com.alexgaoyh.MutiModule.aop.redis.RedisAdvice" >
		<property name="redisTemplate" ref="redisTemplate"></property>
	</bean>
	
	<aop:config>
		<aop:aspect id="aspect" ref="redisHandler">
			<!-- 在多个表达式之间使用  || , or 表示  或 ,使用  && , and 表示  与 , ! 表示  非 -->
			<!-- <aop:pointcut id="pointRedisHandler" expression="execution(* com.alexgaoyh.MutiModule.service.*.*.selectByPrimaryKey(..)) 
					or execution(* com.alexgaoyh.MutiModule.service.*.*.insert(..)) "/> -->
			<aop:pointcut id="pointRedisHandler" expression="execution(* com.alexgaoyh.MutiModule.service.*.*.selectByPrimaryKey(..))"/>		
					
			<!-- <aop:before method="doBefore"  pointcut-ref="pointRedisHandler"/>
			<aop:after method="doAfter"  pointcut-ref="pointRedisHandler"/> -->
			<aop:around method="doAround"  pointcut-ref="pointRedisHandler"/>
			<!-- <aop:after-returning method="doReturn"  pointcut-ref="pointRedisHandler"/>
			<aop:after-throwing method="doThrowing" throwing="ex" pointcut-ref="pointRedisHandler"/> -->
			
		</aop:aspect>
	</aop:config>
	
	<!-- redis 缓存控制层 end-->



这次试用AOP的过程,打算针对不同的方法,设定不同的AOP切面,这样,避免在同一个 doAround 方法中,存在多个 if else 代码块,减少代码耦合的存在,截止到此时,针对select方法,是增加了缓存逻辑,下一步,就可以简单的根据这个方法,同步实现 update insert delete 方法,文章就不进行进一步描述了,直接看代码就行,junit测试也包含。

    在书写过程中,有一个地方需要注意,因为使用redis进行set get操作的时候,value部分是存放的json串,那么,在json->object的时候,就需要获取到转换的object类型。具体实现如下:

package com.alexgaoyh.MutiModule.aop.redis;

import java.io.Serializable;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

public class RedisAdvice {
	
	protected RedisTemplate<Serializable, Serializable> redisTemplate;

	public RedisTemplate<Serializable, Serializable> getRedisTemplate() {
		return redisTemplate;
	}

	public void setRedisTemplate(
			RedisTemplate<Serializable, Serializable> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	/**
	 * 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
	 * 
	 * 注意:当核心业务抛异常后,立即退出,转向After Advice
	 * 执行完毕After Advice,再转到Throwing Advice
	 * Object[] getArgs:返回目标方法的参数  Signature getSignature:返回目标方法的签名 
	 * Object getTarget:返回被织入增强处理的目标对象 Object getThis:返回AOP框架为目标对象生成的代理对象
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	private Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		
		//返回值类型, add 方法将对应的Object 转换为 json 保存到 缓存中,在 get方法的时候,通过下面注释的返回值类型,将json 转换为对应的object
		//pjp.getTarget().getClass().getDeclaredMethod(pjp.getSignature().getName(),((MethodSignature)pjp.getSignature()).getMethod().getParameterTypes()).getReturnType();
		
		// 输出    execution(DemoServiceImpl.insert(..))
		//pjp.toShortString();
		
		//跳转到这里的方法名 形如 insert selectByPrimaryKey
		//pjp.getTarget().getClass().getDeclaredMethod(pjp.getSignature().getName(),((MethodSignature)pjp.getSignature()).getMethod().getParameterTypes()).getName();
		
		String baseKey = pjp.toShortString();
		
		Object[] args = pjp.getArgs();
		//下面这个if判断,针对的是selectByPrimaryKey(Integer id)方法,即 有入参,并且入参的第一个类型为Integer  
		//后期如果有新增方法的话,是需要这里进行数据判断的,可以针对不同的方法,使用不同的切面
        if (args != null && args.length > 0 && args[0].getClass() == Integer.class) {
        	System.out.println("key =  " + baseKey + "_"  + args[0]);
        	
        	ObjectMapper mapper = new ObjectMapper();
        	
        	Object obj = this.get(baseKey + "_"  +args[0]);

        	
        	if(obj == null) {
        		
        		//调用核心逻辑
        		Object retVal = pjp.proceed();
        		
        		this.add(baseKey + "_"  +args[0], mapper.writeValueAsString(retVal));
        		
        		System.out.println("缓存为空");
        		
        		return retVal;
        		
        	}else {
        		
        		System.out.println("缓存不为空");
        		
        		obj = mapper.readValue(obj.toString(), pjp.getTarget().getClass().getDeclaredMethod(pjp.getSignature().getName(),
        				((MethodSignature)pjp.getSignature()).getMethod().getParameterTypes()).getReturnType());

        		return obj;
        	}
        	
        }
		return null;
		
	}

	
	/**
	 * 添加
	 * @param key
	 * @param value
	 */
	public void add(final String key, final String value) {
		if(redisTemplate != null) {
			redisTemplate.execute(new RedisCallback<Object>() {
				@Override
				public Object doInRedis(RedisConnection connection)
						throws DataAccessException {
					connection.set(
							redisTemplate.getStringSerializer().serialize(key),
							redisTemplate.getStringSerializer().serialize(value));
					return null;
				}
			});
		}
    }
	
	/**
     * 根据key获取对象
     */
    public Object get(final String key) {
    	return redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection connection)
					throws DataAccessException {
				
				byte[] keyByte = redisTemplate.getStringSerializer().serialize(key);
				byte[] value = connection.get(keyByte);
				
				String str = redisTemplate.getStringSerializer().deserialize(value);
				
				return str;
			}
    	} );
    }  
	
	 /** 
     * 获取 RedisSerializer 
     * 
     */  
    protected RedisSerializer<String> getRedisSerializer() {  
        return redisTemplate.getStringSerializer();  
    }  
}



执行效果如下图 技术分享

key 的选取,就是使用  

pjp.toShortString() + "_"  + args[0]

这样就能避免key的冲突

并且需要注意下面这一段代码: json->object 的时候,是需要知道当前的数据类型的,获取service层请求方法的返回方法。

//返回值类型, add 方法将对应的Object 转换为 json 保存到 缓存中,在 get方法的时候,通过下面注释的返回值类型,将json 转换为对应的object
		//pjp.getTarget().getClass().getDeclaredMethod(pjp.getSignature().getName(),((MethodSignature)pjp.getSignature()).getMethod().getParameterTypes()).getReturnType();






maven 使用AOP 增加 缓存逻辑 Redis

标签:

原文地址:http://my.oschina.net/alexgaoyh/blog/410965

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!