基于声明式的XML缓存
如果无法使用注释(可能是由于无法访问源代码或没有外部代码),你可以使用XML来进行声明式缓存。因此,你不必在方法上添加缓存注释,而是可以在外部指定目标方法和缓存指令(类似于声明式事务管理的方法建议)。上一节中的示例可以转换为以下示例:
<!-- the service we want to make cacheable -->
<bean id="bookService" class="x.y.service.DefaultBookService"/>
<!-- cache definitions -->
<cache:advice id="cacheAdvice" cache-manager="cacheManager">
<cache:caching cache="books">
<cache:cacheable method="findBook" key="#isbn"/>
<cache:cache-evict method="loadBooks" all-entries="true"/>
</cache:caching>
</cache:advice>
<!-- apply the cacheable behavior to all BookService interfaces -->
<aop:config>
<aop:advisor advice-ref="cacheAdvice" pointcut="execution(* x.y.BookService.*(..))"/>
</aop:config>
<!-- cache manager definition omitted -->
在上述配置中,bookService被设置为可缓存的。应用的缓存语义被封装在cache:advice定义中,该定义规定了使用findBooks方法来将数据放入缓存,以及使用loadBooks方法来清除缓存中的数据。这两个方法都是针对books缓存来操作的。
aop:config 定义通过使用 AspectJ 的切点表达式(更多信息请参见 Spring 的面向切面编程)将缓存建议应用于程序中的相应位置。在前面的例子中,BookService 中的所有方法都被考虑在内,并且缓存建议被应用到这些方法上。
声明式的XML缓存支持所有基于注解的模型,因此在两者之间切换应该相当容易。此外,这两种缓存方式都可以在同一个应用程序中使用。基于XML的方法不会修改目标代码,但相对来说描述性更强(即代码更冗长)。当处理那些需要被缓存的类(其中包含重载方法)时,识别正确的目标方法会稍微增加一些工作量,因为method参数并不足以作为有效的区分依据。在这种情况下,可以使用AspectJ的切点(pointcut)来精确选择需要缓存的方法,并应用相应的缓存功能。不过,通过XML进行缓存配置时,更容易实现针对整个包、组或接口的缓存策略(这同样要归功于AspectJ的切点技术),同时也更容易创建类似模板样的缓存定义(就像我们在前面的例子中通过cache:definitions属性来定义目标缓存那样)。