使用Spring中的aspect或advisor实现方法拦截,模拟缓存实现

2014-11-23 23:35:03 · 作者: · 浏览: 0

AOP是一种将通用逻辑与具体业务分离的技术,能够弥补OO在横向代码复用不足的问题,很好的实现separation of concerns (SoC)。缓存是改善系统性能的一种常用技术,采取以空间换时间的策略。缓存就是与具体业务无关的,如果我们设计一个缓存框架,那么应该是可插拔的,对系统业务代码无侵入的,这很符合AOP的适用场景。我们的项目采用了Ehcache缓存框架作为底层支撑,采用Spring框架的AOP进行方法拦截,将耗时方法的返回结果,进行缓存。现在我们使用spring的aop模拟这种实现。

首先假设我们有一个已经编写好的,比较耗时的类

package net.aty.dao;

public class DaoImpl
{
	public String query(int id)
	{
		// 模拟耗时的数据库查询操作
		try
		{
			System.out.println("query begin...");
			Thread.sleep(100 * id);
			System.out.println("query over...");
		} catch (InterruptedException e)
		{
			e.printStackTrace();
		}

		return "result:" + id * 10;
	}
}

下面是我们编写的缓存实现类

package net.aty.cache;

import java.util.HashMap;
import java.util.Map;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;

public class CacheQueryResult
{
	private Map
  
    buffer = new HashMap
   
    (); public Object around(ProceedingJoinPoint point) throws Throwable { String key = uniqueKey(point); Object returnValue = buffer.get(key); if(returnValue != null) { return returnValue; } Object object = point.proceed(); buffer.put(key, object); return object; } private String uniqueKey(ProceedingJoinPoint point) { Object target = point.getTarget(); Signature signature = point.getSignature(); String methodSignature = signature.toString(); String key = target.hashCode() + methodSignature; return key; } } 
   
  

现在我们在spring.xml中进行配置,实现缓存切面对目标对象的拦截

  

  

	
   
	
   

	
   
	
   

	
    
     
     
      
     
   


  

测试类如下:

package net.aty;

import net.aty.dao.DaoImpl;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMain
{
	private static ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
			"spring.xml");

	public static void main(String[] args)
	{
		for (int i = 0; i < 3; i++)
		{
			testDao();
		}
	}

	public static void testDao()
	{
		DaoImpl dao = (DaoImpl) context.getBean("dao");

		long begin = System.currentTimeMillis();
		String result = dao.query(2);
		long end = System.currentTimeMillis();

		System.out.println(result + ",cost time:" + (end - begin));
	}
}

通过执行结果发现,后面2次调用是直接从缓存中取的数据,这样就达到了我们模拟缓存的效果。

最后附上该工程的结构图和依赖的spring3.1.2的jar

vcq9o6y077W9wcu3vbeowLm92LXE0Ke5+6GjvdPPwsC0yrnTw01ldGhvZEludGVjZXB0b3K6zWFkdmlzb3LN6rPJz+DNrLXE0Ke5+6GjPC9wPgo8cD48cHJlIGNsYXNzPQ=="brush:java;">package net.aty.cache; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class CacheMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("begin MethodInterceptor"); Object result = invocation.proceed(); System.out.println("end MethodInterceptor"); return result; } }
对应的xml配置如下: