maven 使用AOP 增長 緩存邏輯 Redis

    項目搭建過程當中,緩存邏輯在某種程度上,是必不可少了,本文在以前的Maven多模塊項目的基礎上,在service層使用AOP增長了redis緩存邏輯。 java

    具體代碼已上傳git :  http://git.oschina.net/alexgaoyh/MutiModule-parent git

    具體效果,能夠直接執行junit單元測試便可,文章並不針對這些測試進行截圖操做了。 redis

    下面備註上一些須要注意的事項: spring

    

<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類型。具體實現以下: express

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 的選取,就是使用   json

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

這樣就能避免key的衝突 緩存

而且須要注意下面這一段代碼: json->object 的時候,是須要知道當前的數據類型的,獲取service層請求方法的返回方法。 app

//返回值類型, add 方法將對應的Object 轉換爲 json 保存到 緩存中,在 get方法的時候,經過下面註釋的返回值類型,將json 轉換爲對應的object
		//pjp.getTarget().getClass().getDeclaredMethod(pjp.getSignature().getName(),((MethodSignature)pjp.getSignature()).getMethod().getParameterTypes()).getReturnType();
相關文章
相關標籤/搜索