简单的使用缓存的方法,就是在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>]
相关推荐
在IT行业中,Spring AOP(面向切面编程)和EhCache是两个非常重要的概念,它们在提升应用程序性能和管理缓存方面发挥着关键作用。本文将深入探讨如何结合Spring AOP与EhCache实现一个简单的缓存实例,以便优化Java...
本篇文章将详细探讨如何在Spring框架中集成并实现基于方法的缓存机制,利用Ehcache来优化数据访问。 首先,我们需要理解Spring的AOP概念,AOP允许我们定义横切关注点,如日志、事务管理或,正如在这个案例中,缓存...
- **基于注解的AOP(Annotation-based AOP)**:使用`@Aspect`注解定义切面,`@Before`、`@After`、`@Around`等注解定义通知。 **3. 使用步骤** - **配置AOP**:在Spring配置文件中启用AOP支持,如 `<aop:aspectj-...
至此,我们就完成了使用自定义注解实现的Spring Boot和Redis缓存机制。通过这种方式,我们可以灵活地控制哪些方法的结果应该被缓存,并且可以根据业务需求调整缓存策略,如过期时间、键生成规则等。同时,得益于...
例如,可以使用引入让任何对象实现`IsModified`接口,从而简化缓存操作。 6. **目标对象(Target Object)**:包含了连接点的对象,即被通知的对象。在Spring AOP中,这个对象通常是业务逻辑实现类。 7. **AOP代理...
Spring AOP 1.0是Spring框架早期的一个版本,它引入了面向切面编程(Aspect Oriented Programming,AOP)的概念,使得开发者可以方便地实现横切关注点,如日志记录、事务管理、性能监控等,从而提高代码的可读性和可...
**Spring AOP实现方式** 1. **注解驱动(Annotation-based)**:使用`@Aspect`注解定义切面,`@Before`, `@After`, `@AfterReturning`, `@AfterThrowing`, `@Around`定义通知,`@Pointcut`定义切入点表达式。 2. *...
SpringBoot AOP,即面向切面编程,是Spring框架中的一个重要特性,用于实现代码的横切关注点,如日志记录、事务管理、权限验证等。AOP通过使用代理模式,将这些关注点与核心业务逻辑分离,使得代码更加模块化,更...
- Spring AOP基于代理,只能在方法调用层面织入,而AspectJ可以在编译时或运行时通过字节码操作实现更细粒度的织入,支持字段和构造器级别的切点。 - AspectJ提供了更强大的切入点表达式和通知模型,但配置和使用...
JDK动态代理基于接口实现,适用于目标对象实现了接口的情况;而CGLIB代理则是在运行时动态生成一个目标类的子类来实现,当目标对象没有实现接口时,Spring会选择使用CGLIB。 AOP的核心概念包括切面(Aspect)、通知...
Struts1.3、Spring2.5 和 Hibernate3.3 是经典的 Java Web 开发框架组合,它们在企业级应用中广泛...同时,深入研究 Spring 的 AOP、事务管理以及 Hibernate 的缓存策略,将有助于提升开发水平和解决复杂问题的能力。
总之,`applicationContext-service.xml`文件是SSM架构中Service层的核心配置,它定义了Service组件的生命周期、依赖关系和行为,是实现业务逻辑的关键部分。理解和熟练配置这个文件,对于提升Java企业级应用的开发...
Hibernate还支持二级缓存和事务管理,提高了性能和数据一致性。 **整合过程** 整合SpringMVC、Spring和Hibernate通常涉及以下几个步骤: 1. **配置pom.xml**:引入所需的库依赖,如Spring、SpringMVC、Hibernate、...
2. 框架配置:Spring框架中的`@Component`、`@Service`、`@Repository`和`@Controller`等用于组件扫描和依赖注入。 3. 缓存管理:例如Hibernate的`@Cacheable`用于缓存查询结果。 4. 验证:JSR 303/349的`@Valid`和`...
Struts2、Spring和Hibernate是Java Web开发中的三大框架,它们各自负责不同的职责:Struts2专注于MVC(Model-View-Controller)架构的实现,Spring提供了强大的依赖注入(DI)和面向切面编程(AOP)功能,而...
Spring的`@Autowired`注解可以自动装配依赖,`@Service`、`@Repository`和`@Controller`等注解则有助于代码组织和职责划分。 5. **Annotation**:注解是Java语言的一个重要特性,它允许在代码中嵌入元数据,从而...
**Spring** 是一个全面的Java企业级应用开发框架,它以依赖注入(DI)和面向切面编程(AOP)为核心,提供事务管理、数据访问集成、邮件服务等功能。Spring3.1版本引入了更多改进,如对Java配置的支持,使配置更简洁...
这三种框架的结合提供了模型-视图-控制器(MVC)架构、对象关系映射(ORM)以及依赖注入(DI)和面向切面编程(AOP)的能力,从而简化了复杂的应用开发流程。 **Struts1.3** 是一个基于MVC设计模式的Java Web框架,...
这两种方式都实现了相同的目标——创建一个AOP切面,从而使得带有特定缓存注解的方法能够触发缓存逻辑。 #### 缓存管理器详解 缓存管理器是Spring缓存框架的核心组件之一,负责管理缓存的具体实现以及缓存的生命...
当然,实际应用中可能需要更复杂的限制策略,如基于IP地址、用户ID、会话ID等,这可能需要结合缓存服务(如Redis)或数据库来存储和查询访问记录。 除了手动实现外,Spring Cloud Gateway和Spring Cloud Zuul等...