您的位置:首页 > 编程语言 > Java开发

spring Aop 之方法缓存

2016-03-10 16:05 363 查看
    因为公司人手原因,最近在为项目搭建架构,在异常,缓存,日志,方面都打算用Aop来做,在原来的项目中对在对异常,日志方面可能都是Log log=Logfactory.getLog();这样既麻烦,又紧耦合在一起。所以打算用Aop试试。下面是对一些缓存对象的Aop处理。主要是根据方法签名来做key值。

    定义一个注解

  

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodCache {
int second() default 0;
}

 

    定义一个业务处理类

 

public class Sev {
@MethodCache(second=3)
public Map getSort(int type,int parentid){
System.out.println("no cache----");
Map m =new HashMap();
return m;
}

@MethodCache(second=3)
public void getSort(){
System.out.println("no cache----");
}
}

 

   定义一个Aop

 

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Date;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MethodCacheAspectJ {

private Cache cache;

/**
* 设置缓存名
*/
public void setCache(Cache cache) {
this.cache = cache;
}

@Pointcut("@annotation(com.zhang.shine.cache.MethodCache)")
public void methodCachePointcut(){
}

@Around("methodCachePointcut()")
public Object methodCacheHold(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("aop start ");
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Object result = null;
String cacheKey = getCacheKey(targetName, methodName, arguments);
System.out.println("key--"+cacheKey);
Element element = cache.get(cacheKey);
if (element == null) {
try{
result = joinPoint.proceed();
}catch(Exception e){

}
if(result!=null){
try{
element = new Element(cacheKey, (Serializable) result);
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
int second = 0;
for(Method m:method){
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if(tmpCs.length==arguments.length){
MethodCache methodCache = m.getAnnotation(MethodCache.class);
second = methodCache.second();
break;
}
}
}
if(second>0){ // annotation没有设second值则使用ehcache.xml中自定义值
element.setTimeToIdle(second);
element.setTimeToLive(second);
}
cache.put(element);
}catch(Exception e){
}
}
}
System.out.println("aop end ");
return element.getValue();
}

private String getCacheKey(String targetName, String methodName,
Object[] arguments) {
StringBuffer sb = new StringBuffer();
sb.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
if (arguments[i] instanceof Date) {
sb.append(".").append(
DateUtil.datetoString((Date) arguments[i]));
} else {
sb.append(".").append(arguments[i]);
}
}
}
return sb.toString();
}
}

 

    Spring配置文件

   

<bean id = "methodCacheAspectJ" class="com.zhang.shine.cache.MethodCacheAspectJ" >
<property name="cache">
<!-- <ref local="methodCache" /> -->
<ref bean="methodCache"/>
</property>
</bean>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>

<!-- 定义ehCache的工厂,并设置所使用的Cache name -->

<bean id="methodCache"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager" />
</property>
<property name="cacheName">
<value>DEFAULT_CACHE</value>
</property>
</bean>
<bean id="sev" class="com.zhang.shine.cache.Sev"></bean>

 

    ehcache.xml

  

 

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="/home/workspace/gzshine/trunk/ehcache"/>

<defaultCache
maxElementsInMemory="50000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="7200"
timeToLiveSeconds="7200"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"/>

<cache name="DEFAULT_CACHE"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="true"
/>
</ehcache>

 

   测试类

 

package test;

import net.sf.cglib.core.DebuggingClassWriter;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.zhang.shine.cache.CallImpl;
import com.zhang.shine.cache.MyImpl;
import com.zhang.shine.cache.Sev;
import sun.misc.*;
/**
* 1.产生代理类$Proxy0类

执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;

2.   将代理类$Proxy0类加载到JVM中

这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中

3.   创建代理类$Proxy0类的对象

调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象

参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数

这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现;

4.   生成代理类的class byte

动态代理生成的都是二进制class字节码

* @author zhang_zengmin
*
*/
public class TestAOP {
public static void main(String[] args) throws Exception{
//cglib 代理对象class文件输出目录 如果是jdk动态代理就不输出
/**
* cglib头部信息
public class Sev$$EnhancerByCGLIB$$bb4c2585 extends Sev
implements SpringProxy, Advised, Factory
*/
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,  "c://class" );

ApplicationContext ap =new ClassPathXmlApplicationContext("ApplicationContent.xml");
Sev s = (Sev)ap.getBean("sev");
//Sev s = new Sev();
s.getSort(1, 2);
//Thread.sleep(3010);
s.getSort(1, 3);
// s.getSort();
System.out.println(s.getClass());

MyImpl my=(MyImpl)ap.getBean("my");

my.pao();
//动态代理获取字节码  头部信息
//public final class $Proxy0 extends Proxy implements Manager {

/*byte[] proxyClassFile =	ProxyGenerator.generateProxyClass(
proxyName, interfaces);*/

/**
* 接口默认Jdk代理
*/
// ICall call = (ICall)ap.getBean("call");

// call.cll();

// Thread.sleep(60000);

/* Enhancer enhancer = new Enhancer();//通过类Enhancer创建代理对象
enhancer.setSuperclass(Sev.class);//传入创建代理对象的类

ClassReader cr = new ClassReader(enhancer.getClass().getName());

byte[] a = cr.b;
File f =new File("c://Sev.class");
FileOutputStream  fout = new FileOutputStream(f);
fout.write(a);
fout.flush();
fout.close();*/

}
}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: