`

Spring AOP简化资源池管理

 
阅读更多

在开发过程中,我们常会用到一些资源池,比如线程池、数据库连接池。在操作这些资源池之后,往往要将一开始得到的资源池对象释放回资源池。

在代码中通常这样实现

try {
    //从资源池获取一个资源,进行业务处理
} catch (Exception e) {
    //异常处理
}finally {
    //释放资源到资源池
}

每次进行业务逻辑处理的时候都这样写是不是很麻烦?使用AOP可以简化代码。

我们以JedisPool为例演示代码。JedisPool是一个典型的资源池,初始化一次,以后每次从里面得到jedis对象,用完后释放回JedisPool里面。

AOP相关知识请参考http://ye-liang.iteye.com/blog/2010797

JedisPool相关知识请参考http://ye-liang.iteye.com/blog/1998177

另外还用到了ThreadLocal类,相关知识请参考http://ye-liang.iteye.com/blog/2009763

 

操作JedisPool的工具类JedisPoolUtil,里面有初始化、获取一个jedis对象、释放资源等方法。

public class JedisPoolUtil {
	private static JedisPool pool = null;
	private static final int maxAcive = 3000;
	private static final int maxIdle = 2000;
	private static final long maxWait = 100000L;
	private static final boolean  testOnBorrow = false;
	private static final boolean  testWhileIdle = true;
	private static final int minEvictableIdleTime = 60000;
	private static final int timeBetweenEvictionRuns = 30000;
	private static final int numTestsPerEvictionRun = -1;
	private static final String redisIp = SystemCodes.redisIP;
	private static final int port = SystemCodes.redisPort;

	static {
		initialPool();
	}

	private static void initialPool() {
		try {
			JedisPoolConfig config = new JedisPoolConfig();
			config.setMaxActive(maxAcive);
			config.setMaxIdle(maxIdle);
			config.setMaxWait(maxWait);
			config.setTestOnBorrow(testOnBorrow);
			config.setTestWhileIdle(testWhileIdle);
			config.setMinEvictableIdleTimeMillis(minEvictableIdleTime);
			config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRuns);
			config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
			pool = new JedisPool(config, redisIp, port);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public static Jedis getJedis() {
		Jedis jedis = pool.getResource();
		return jedis;
	}
	
	
	public static void releaseJedis(Jedis jedis) {
		if (null != jedis) {
			try {
				pool.returnResource(jedis);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void returnBrokenResource(Jedis jedis) {
		if (null != jedis) {
			try {
				pool.returnBrokenResource(jedis);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static Jedis getSingleJedis(){
		Jedis jedisSingle = new Jedis(redisIp, port);
		return jedisSingle;
	}
	
	public static void releaseSingleJedis(Jedis jedis){
		if(null != jedis){
			try {
				jedis.disconnect();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

JedisManager类。进一步封装了JedisPoolUtil的方法,用在本文一开始的try catch finally代码里面。因为在切面和dao里面都要用到jedis对象,为了简化代码,把jedis对象存在该类的ThreadLocal里面。

public class JedisManager {
	private static ThreadLocal<Jedis> localJedis = new ThreadLocal<Jedis>();

	public static void begin() {
		if (localJedis.get() == null || (Jedis) localJedis.get() == null) {
			Jedis jedis = JedisPoolUtil.getJedis();
			localJedis.set(jedis);
		}
	}

	public static Jedis getJedis(){
		return (Jedis)localJedis.get();
	}
	
	public static void returnBrokenResource(){
		Jedis jedis = (Jedis)localJedis.get();
		JedisPoolUtil.returnBrokenResource(jedis);
	}
	
	public static void releaseJedis(){
		Jedis jedis = (Jedis)localJedis.get();
		JedisPoolUtil.releaseJedis(jedis);
		localJedis.remove();
	}
}

 

切面类JedisAspect。这里我们用@Aspect方式实现AOP,所以spring配置文件需要引入<aop:aspectj-autoproxy proxy-target-class="true" />。

@Aspect
public class JedisAspect {
	// 定义切入点
	@Pointcut(value = "execution(* com.springaop.TestService.test(..))")
	public void jedisPointcut() {
	}

	// 环绕
	@Around(value = "jedisPointcut()")
	public void arondAdvice(ProceedingJoinPoint jp) throws Throwable {
		System.out.println("===========around advice");
		try {
			JedisManager.begin();
			jp.proceed();
		} catch (Throwable e) {
			JedisManager.returnBrokenResource();
			throw e;
		}finally {
			JedisManager.releaseJedis();
		}
	}
}

切入点定义到service层。这里采用环绕通知的方式。jp.proceed()相当于调用目标对象。整个过程用try catch finally 包起来。一开始JedisManager.begin()获取jedis对象存到该线程的ThreadLocal里面。遇到异常释放jedis对象,最后将jedis对象返回资源池。

在dao里面要获取jedis对象就调用

Jedis jedis = JedisManager.getJedis();

 

这样service和dao层完全没有了一大推的try catch finally 。都交给了切面里面的通知方法去完成,只用写一次。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics