网站怎么做站长统计,互联网推广有哪些,中国有哪些软件公司,网页qq登录入口首页介绍 记忆化是一种方法级别的缓存技术#xff0c;用于加快连续调用的速度。 这篇文章将演示如何仅使用Spring AOP实现任何数据源的请求级可重复读取。 Spring缓存 Spring提供了非常有用的缓存抽象 #xff0c;允许您将应用程序逻辑与缓存实现细节分离。 Spring Caching使用… 介绍 记忆化是一种方法级别的缓存技术用于加快连续调用的速度。 这篇文章将演示如何仅使用Spring AOP实现任何数据源的请求级可重复读取。 Spring缓存 Spring提供了非常有用的缓存抽象 允许您将应用程序逻辑与缓存实现细节分离。 Spring Caching使用应用程序级范围因此对于仅请求的备忘录我们需要采用DIY方法。 请求级缓存 请求级缓存条目生命周期始终绑定到当前请求范围。 这种缓存与提供会话级可重复读取的 Hibernate Persistence Context非常相似。 为了防止更新丢失 甚至对于NoSQL解决方案必须进行可重复的读取 。 分步实施 首先我们将定义一个“记忆标记”注释 Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
public interface Memoize {
} 该注释将显式标记所有需要记住的方法。 为了区分不同的方法调用我们将方法调用信息封装为以下对象类型 public class InvocationContext {public static final String TEMPLATE %s.%s(%s);private final Class targetClass;private final String targetMethod;private final Object[] args;public InvocationContext(Class targetClass, String targetMethod, Object[] args) {this.targetClass targetClass;this.targetMethod targetMethod;this.args args;}public Class getTargetClass() {return targetClass;}public String getTargetMethod() {return targetMethod;}public Object[] getArgs() {return args;}Overridepublic boolean equals(Object that) {return EqualsBuilder.reflectionEquals(this, that);}Overridepublic int hashCode() {return HashCodeBuilder.reflectionHashCode(this);}Overridepublic String toString() {return String.format(TEMPLATE, targetClass.getName(), targetMethod, Arrays.toString(args));}
} 很少有人知道Spring Request / Session bean的作用域。 因为我们需要一个请求级的备忘录作用域所以我们可以使用Spring请求作用域来简化我们的设计该作用域隐藏了实际的HttpSession解析逻辑 Component
Scope(proxyMode ScopedProxyMode.TARGET_CLASS, value request)
public class RequestScopeCache {public static final Object NONE new Object();private final MapInvocationContext, Object cache new HashMapInvocationContext, Object();public Object get(InvocationContext invocationContext) {return cache.containsKey(invocationContext) ? cache.get(invocationContext) : NONE;}public void put(InvocationContext methodInvocation, Object result) {cache.put(methodInvocation, result);}
} 由于没有运行时处理引擎仅注释就没有任何意义因此我们必须定义一个实现实际备注逻辑的Spring Aspect Aspect
public class MemoizerAspect {Autowiredprivate RequestScopeCache requestScopeCache;Around(annotation(com.vladmihalcea.cache.Memoize))public Object memoize(ProceedingJoinPoint pjp) throws Throwable {InvocationContext invocationContext new InvocationContext(pjp.getSignature().getDeclaringType(),pjp.getSignature().getName(),pjp.getArgs());Object result requestScopeCache.get(invocationContext);if (RequestScopeCache.NONE result) {result pjp.proceed();LOGGER.info(Memoizing result {}, for method invocation: {}, result, invocationContext);requestScopeCache.put(invocationContext, result);} else {LOGGER.info(Using memoized result: {}, for method invocation: {}, result, invocationContext);}return result;}
}测试时间 让我们对所有这些进行测试。 为了简单起见我们将使用Fibonacci数字计算器模拟请求级范围的备忘需求 Component
public class FibonacciServiceImpl implements FibonacciService {Autowiredprivate ApplicationContext applicationContext;private FibonacciService fibonacciService;PostConstructprivate void init() {fibonacciService applicationContext.getBean(FibonacciService.class);}Memoizepublic int compute(int i) {LOGGER.info(Calculate fibonacci for number {}, i);if (i 0 || i 1)return i;return fibonacciService.compute(i - 2) fibonacciService.compute(i - 1);}
} 如果我们要计算第十个斐波那契数我们将得到以下结果 Calculate fibonacci for number 10
Calculate fibonacci for number 8
Calculate fibonacci for number 6
Calculate fibonacci for number 4
Calculate fibonacci for number 2
Calculate fibonacci for number 0
Memoizing result 0, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([0])
Calculate fibonacci for number 1
Memoizing result 1, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([1])
Memoizing result 1, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([2])
Calculate fibonacci for number 3
Using memoized result: 1, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([1])
Using memoized result: 1, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([2])
Memoizing result 2, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([3])
Memoizing result 3, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([4])
Calculate fibonacci for number 5
Using memoized result: 2, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([3])
Using memoized result: 3, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([4])
Memoizing result 5, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([5])
Memoizing result 8, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([6])
Calculate fibonacci for number 7
Using memoized result: 5, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([5])
Using memoized result: 8, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([6])
Memoizing result 13, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([7])
Memoizing result 21, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([8])
Calculate fibonacci for number 9
Using memoized result: 13, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([7])
Using memoized result: 21, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([8])
Memoizing result 34, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([9])
Memoizing result 55, for method invocation: com.vladmihalcea.cache.FibonacciService.compute([10])结论 备注是一个贯穿各领域的问题Spring AOP允许您将缓存详细信息与实际的应用程序逻辑代码分离。 代码可在GitHub上获得 。 翻译自: https://www.javacodegeeks.com/2014/12/spring-request-level-memoization.html