概述
如果不想使用注解或者由于其他原因无法获得项目的源码等,Spring也支持使用XML的方式配置Spring Cache,主要是通过类似于aop:advice的cache:advice来进行的。
在cache命名空间下定义了一个cache:advice元素用来定义一个对于Cache的advice。其需要指定一个cache-manager属性,默认为cacheManager。
cache:advice下面可以指定多个cache:caching元素,其有点类似于使用注解时的@Caching注解。
cache:caching元素下又可以指定cache:cacheable、cache:cache-put和cache:cache-evict元素,它们类似于使用注解时的@Cacheable、@CachePut和@CacheEvict。
示例
项目结构:
数据库表数据(Oracle):
实体类
package com.xgj.cache.springCacheXml.domain; import java.io.Serializable; /** * * * @ClassName: LittleArtisan * * @Description: Java中的缓存和序列化是息息相关的,注意实现Serializable接口 * * @author: Mr.Yang * * @date: 2017年10月2日 下午1:40:53 */ public class LittleArtisan implements Serializable { private static final long serialVersionUID = 1L; private String artisanId; private String artisanName; private String artisanDesc; public String getArtisanId() { return artisanId; } public void setArtisanId(String artisanId) { this.artisanId = artisanId; } public String getArtisanName() { return artisanName; } public void setArtisanName(String artisanName) { this.artisanName = artisanName; } public String getArtisanDesc() { return artisanDesc; } public void setArtisanDesc(String artisanDesc) { this.artisanDesc = artisanDesc; } public static long getSerialversionuid() { return serialVersionUID; } }
服务层
package com.xgj.cache.springCacheXml.service; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowCallbackHandler; import com.xgj.cache.springCacheXml.domain.LittleArtisan; /** * * * @ClassName: LittleArtisanSpringCacheService * * @Description: * * @author: Mr.Yang * * @date: 2017年10月4日 上午12:41:32 */ public class LittleArtisanSpringCacheService { private Logger logger = Logger .getLogger(LittleArtisanSpringCacheService.class); private static final String selectArtisanSQL = "select artisan_id ,artisan_name ,artisan_desc from little_artisan where artisan_name = ?"; private JdbcTemplate jdbcTemplate; @Autowired public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } /** * * * @Title: getArtisan * * @Description: getArtisan 通过在xml中配置 缓存数据 * * @param artisanName * @return * * @return: LittleArtisan */ public LittleArtisan getArtisan(String artisanName) { // 方法内部实现不考虑缓存逻辑,直接实现业务 System.out.println("查找Artisan:" + artisanName); return getFromDB(artisanName); } /** * * * @Title: reloadArtisan * * @Description: 清除缓存 * * * @return: void */ public void reloadArtisan() { System.out.println("cache cleared"); } /** * * * @Title: getFromDB * * @Description: 从数据库中获取LittleArtisan * * @param artisanName * @return * * @return: LittleArtisan */ private LittleArtisan getFromDB(String artisanName) { System.out.println("getFromDB"); final LittleArtisan littleArtisan = new LittleArtisan(); jdbcTemplate.query(selectArtisanSQL, new Object[] { artisanName }, new RowCallbackHandler() { @Override public void processRow(ResultSet rs) throws SQLException { littleArtisan.setArtisanId(rs.getString("artisan_id")); littleArtisan.setArtisanName(rs .getString("artisan_name")); littleArtisan.setArtisanDesc(rs .getString("artisan_desc")); } }); return littleArtisan; } }
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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!-- 扫描注入注解,比如@Autowired --> <context:component-scan base-package="com.xgj.cache.springCacheXml"/> <!-- 使用context命名空间,加载数据库的properties文件 --> <context:property-placeholder location="classpath:spring/jdbc.properties" /> <!-- 数据库 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" /> <!-- 配置namedParameterJdbcTemplate模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg ref="dataSource"/> </bean> <!-- 定义需要使用缓存的类 --> <bean id="littleArtisanSpringCacheService" class="com.xgj.cache.springCacheXml.service.LittleArtisanSpringCacheService"/> <!-- 缓存管理器 使用SimpleCacheManager,基于JDK的实现--> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="littleArtisan"/> </set> </property> </bean> <!-- 缓存定义 --> <cache:advice id="cacheAdvice" cache-manager="cacheManager" > <cache:caching cache="littleArtisan"> <!-- 公共缓存littleArtisan --> <cache:cacheable method="getArtisan" key="#artisanName"/> <!-- getArtisan使用 Cacheable --> <cache:cache-evict method="reloadArtisan" all-entries="true"/><!-- reloadArtisan使用 CacheEvict --> </cache:caching> </cache:advice> <!-- 切面增强 --> <aop:config> <aop:pointcut id="cachePoint" expression="execution(* com.xgj.cache.springCacheXml.service.LittleArtisanSpringCacheService.*(..))" /> <aop:advisor advice-ref="cacheAdvice" pointcut-ref="cachePoint"/> </aop:config> </beans>
单元测试
package com.xgj.cache.springCacheXml.service; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.xgj.cache.springCacheXml.domain.LittleArtisan; public class TestXmlCache { ClassPathXmlApplicationContext context = null; LittleArtisanSpringCacheService service = null; LittleArtisan littleArtisan; @Before public void initContext() { // 启动Spring 容器 context = new ClassPathXmlApplicationContext( "classpath:com/xgj/cache/springCacheXml/conf_spring.xml"); } @Test public void testXmlCache() { service = context.getBean( "littleArtisanSpringCacheService", LittleArtisanSpringCacheService.class); // 第一次 从数据库加载 littleArtisan = service.getArtisan("masterArtisan"); printArtisan(); // 第二次 从缓存加载 littleArtisan = service.getArtisan("masterArtisan"); printArtisan(); // 清空缓存 service.reloadArtisan(); // 再次查询,从数据库加载 service.getArtisan("masterArtisan"); printArtisan(); // 又查询,从缓存加载 service.getArtisan("masterArtisan"); printArtisan(); } private void printArtisan() { System.out.println(littleArtisan.getArtisanName() + "||" + littleArtisan.getArtisanDesc()); } @After public void releaseContext() { if (context != null) { context.close(); } } }
日志输出
2017-10-04 08:40:00,529 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@403d0d64: startup date [Wed Oct 04 08:40:00 BOT 2017]; root of context hierarchy 2017-10-04 08:40:00,623 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/cache/springCacheXml/conf_spring.xml] 查找Artisan:masterArtisan getFromDB masterArtisan||Spring Cache masterArtisan||Spring Cache cache cleared 查找Artisan:masterArtisan getFromDB masterArtisan||Spring Cache masterArtisan||Spring Cache 2017-10-04 08:40:03,433 INFO [main] (AbstractApplicationContext.java:984) - Closing org.springframework.context.support.ClassPathXmlApplicationContext@403d0d64: startup date [Wed Oct 04 08:40:00 BOT 2017]; root of context hierarchy
日志分析
第一次从数据库中加载,第二次没有打印getFromDB,说明是从缓存中取的数据。 然后清空缓存,第一次从数据库中加载,第二次从缓存中取的数据。
示例源码
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster