简单的使用缓存的方法,就是在Service中嵌入调用缓存的代码。
1.先查询缓存,
2.若缓存命中,则返回
3.从数据库查询,并且往缓存中插入一份
这种做法导致许多许多重复代码,所以想到了用注解来调用缓存。并且在注解中设置key和expire
先定义注解
package com.cache; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MethodCache { String prefix(); int expire(); }
定义一个简单的Service类,并对需要走缓存的方法加上注解。注意此处注解中的prefix写成这个样子,是为了告诉Aspect要获取的属性,以便能够动态生成key。
package com.cache; import com.user.vo.User; import org.springframework.stereotype.Component; @Component("userService2") public class UserService { @MethodCache(prefix = "'user_'+#userId", expire = 100) public User get(User user) { System.out.println("Calling Service..."); user.setName("hisky"); return user; } }
定义一个简单的CacheManager类
package com.cache; import org.springframework.stereotype.Component; import java.util.concurrent.ConcurrentHashMap; @Component public class CacheManager { private ConcurrentHashMap cache = new ConcurrentHashMap(); public Object get(String key) { Object value = cache.get(key); return value; } public void put(String key, Object value) { cache.put(key, value); } }
重点来了!定义一个Aspect,截获有注解的方法。
package com.cache; import com.sun.javafx.binding.StringFormatter; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @org.aspectj.lang.annotation.Aspect @Component public class CacheAspect { @Autowired private CacheManager cacheManager; @Pointcut("@annotation(com.cache.MethodCache)") public void pointCut() { } @Around("pointCut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { String key = getKey(pjp); Object cachedObj = cacheManager.get(key.toString()); System.out.println(String.format("Find the object from cache, key=%s,value=%s", key, cachedObj)); if (cachedObj != null) { return cachedObj; } System.out.println("Find nothing from cache, keep call service."); cachedObj = pjp.proceed(pjp.getArgs()); System.out.println(String.format("Put the object to cache, key=%s,value=%s", key, cachedObj)); cacheManager.put(key.toString(), cachedObj); return cachedObj; } public String getKey(ProceedingJoinPoint pjp) { MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); Method method = methodSignature.getMethod(); Annotation annotation = method.getAnnotation(MethodCache.class); String prefix = ((MethodCache) annotation).prefix(); Object args[] = pjp.getArgs(); String key = SpringELParser.parseKey(prefix, args[0]); return key; } }
为了支持动态的生成Key,此处引入Spring EL解析注解的Key
package com.cache; import com.user.vo.User; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class SpringELParser { private static ExpressionParser parser = new SpelExpressionParser(); // private static Logger log = Logger.getLogger(SpelParser.class); // String prefix = "'Book.'+#bookId"; // int bookId = 100; public static String parseKey(String key, String condition, String[] paramNames, Object[] arguments) { try { if (!checkCondition(condition, paramNames, arguments)) { return null; } Expression expression = parser.parseExpression(key); EvaluationContext context = new StandardEvaluationContext(); int length = paramNames.length; if (length > 0) { for (int i = 0; i < length; i++) { context.setVariable(paramNames[i], arguments[i]); } } return expression.getValue(context, String.class); } catch (Exception e) { e.printStackTrace(); return null; } } public static boolean checkCondition(String condition, String[] paramNames, Object[] arguments) { if (condition.length() < 1) { return true; } Expression expression = parser.parseExpression(condition); EvaluationContext context = new StandardEvaluationContext(); int length = paramNames.length; if (length > 0) { for (int i = 0; i < length; i++) { context.setVariable(paramNames[i], arguments[i]); } } return expression.getValue(context, boolean.class); } public static String parseKey(String prefix, Object arg) { String key = ""; try { String param = getParam(prefix); Object value = getValue(arg, param); key = parseKey(prefix, "", new String[]{param}, new Object[]{value}); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return key; } private static Object getValue(Object arg, String param) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { String methodName = getMethodName(param); Class clzz = arg.getClass(); Method method = clzz.getMethod(methodName); return method.invoke(arg); } private static String getParam(String prefix) { return prefix.substring(prefix.lastIndexOf("#") + 1); } private static String getMethodName(String param) { return "get" + param.substring(0, 1).toUpperCase() + param.substring(1); } public static void main(String[] args) { try { String prefix = "'user_'+#userId"; User user = new User(); user.setUserId(123); String key = parseKey(prefix, user); System.out.println(key); } catch (Exception e) { e.printStackTrace(); } } }
Spring的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd" default-lazy-init="true"> <context:component-scan base-package="com.*"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/> </context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
测试类
package com.cache; import com.user.vo.User; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AOPTest { public static void main(String args[]) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/cache/spring-test.xml"); UserService service = (UserService) ctx.getBean("userService2"); User user = new User(); user.setUserId(1); service.get(user); service.get(user); } }
从控制台可以看出,此处生成的key为user_1。第一次缓存查不到,则调用service获取。第二次则从缓存直接返回了。
Find the object from cache, key=user_1,value=null Find nothing from cache, keep call service. Calling Service... Put the object to cache, key=user_1,value=com.user.vo.User@45667d98[userId=1,name=hisky,password=<null>,type=<null>] Find the object from cache, key=user_1,value=com.user.vo.User@45667d98[userId=1,name=hisky,password=<null>,type=<null>]
相关推荐
基于annotation的aop实现 动态代理理念(study content Aspect)
AutoLoadCache 是基于AOP Annotation等技术实现的高效的缓存管理解决方案,实现缓存与业务逻辑的解耦,并增加异步刷新及“拿来主义机制”,以适应高并发环境下的使用。
Spring_Annotation_AOP
http://blog.csdn.net/shan9liang/article/details/22295841 EJB+Annotation实现AOP的DEMO
反射、Annotation与aop技术文档 反射、Annotation与aop技术文档,
详解 Spring 3.0 基于 Annotation 的依赖注入实现。。详解 Spring 3.0 基于 Annotation 的依赖注入实现。。
NULL 博文链接:https://whp0731.iteye.com/blog/356167
NULL 博文链接:https://tianhei.iteye.com/blog/978969
基于annotation s2sh实现零配置的CRM
基于annotation s2sh实现零配置的教务管理系统
设计思想及原理使用方法注解(Annotation)说明表达式的应用缓存删除注意事项缓存管理页面与Spring Cache的区别源码阅读已经实现基于aspectj,代码在com.jarvis.cache.aop.aspectj.AspectjAopInterceptor。想通过...
基于annotation s2sh实现零配置的教务管理系统改进版
详解Spring基于Annotation的依赖注入实现
基于Annotation的s2sh整合配置实现分页功能基于Annotation的s2sh整合配置实现分页功能基于Annotation的s2sh整合配置实现分页功能基于Annotation的s2sh整合配置实现分页功能基于Annotation的s2sh整合配置实现分页功能
详解Spring_3.0基于Annotation的依赖注入实现
NULL 博文链接:https://baobeituping.iteye.com/blog/1201798
初学者很好的学习资料哦,注意哦,这可是基于annotation的 SSH哦,xml的时代已经过去了
Spring mvc Aop+annotation实现系统日志记录功能实现的jar包asm-3.3.jar ,aspectjrt.jar , aspectjweaver.jar , cglib-nodep-2.1_3.jar , spring-aop.jar