spring+redis 实现缓存 解决序列化和反序列化的问题
1.config.properties
# Redis settings
redis.host=127.0.0.1
redis.port=6379
#redis.pass=password
redis.dbIndex=0
redis.expiration=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true
2.spring-context.xml
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.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"
>
<!-- 自动扫描 -->
<context:component-scan base-package="com.bigname" />
<!-- 读入配置属性文件 -->
<!-- <context:property-placeholder location="classpath:config.properties" />
<context:property-placeholder location="classpath:pgsql-config.properties" />
-->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config.properties</value>
<value>classpath:pgsql-config.properties</value>
</list>
</property>
</bean>
<!-- 引入spring-redis.xml -->
<import resource="classpath:spring-redis.xml" />
<!-- 配置c3p0 -->
<!-- 连接池 -->
<!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost/qw?characterEncoding=utf8&serverTimezone=UTC"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
<property name="minPoolSize" value="1"></property>
<property name="maxPoolSize" value="5"></property>
<property name="initialPoolSize" value="1"></property>
<property name="acquireIncrement" value="1"></property>
</bean> -->
<!-- 定义数据库连接池数据源bean destroy-method="close"的作用是当数据库连接不使用的时候,就把该连接重新放到数据池中,方便下次使用调用 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- 设置JDBC驱动名称 -->
<property name="driverClass" value="${jdbc.driver}" />
<!-- 设置JDBC连接URL -->
<property name="jdbcUrl" value="${jdbc.url}" />
<!-- 设置数据库用户名 -->
<property name="user" value="${jdbc.username}" />
<!-- 设置数据库密码 -->
<property name="password" value="${jdbc.password}" />
<!-- 设置连接池初始值 -->
<property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
<!-- 设置连接池最大值 -->
<property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property>
<!-- 设置连接池最小值 -->
<property name="minPoolSize" value="${c3p0.minPoolSize}"></property>
<property name="maxIdleTime" value="${c3p0.maxIdleTime}"></property>
<property name="acquireIncrement" value="${c3p0.acquireIncrement}"></property>
<property name="maxIdleTimeExcessConnections" value="${c3p0.maxIdleTimeExcessConnections}"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 使用注解来控制事务 -->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!-- 配置mybatis, 绑定c3p0-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations">
<list>
<value>classpath:mapper/*.xml</value>
</list>
</property>
</bean>
<!-- 扫描生成所有dao层 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.bigname.demo.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
3.spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:redis="http://www.springframework.org/schema/redis" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/redis
http://www.springframework.org/schema/redis/spring-redis.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
">
<!-- Redis -->
<!-- 连接池参数 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxActive}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<!-- 配置JedisConnectionFactory -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<!-- <property name="password" value="${redis.pass}" /> -->
<property name="database" value="${redis.dbIndex}" />
<property name="poolConfig" ref="poolConfig" />
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<!-- 配置默认的序列化策略,非hash的value和hashValue都有效-->
<property name="defaultSerializer" ref="genericJackson2JsonRedisSerializer">
</property>
<!--<!– 配置redis的key的序列化Serializer方式,使5中类型,key都以String类型进行序列化 –>-->
<!--<!– Hash类型,用Jedis存储key为brandList,但是在redis-cli中查看key却是 "\xac\xed\x00\x05t\x00\tbrandList" –>-->
<property name="keySerializer" ref="stringRedisSerializer" />
<property name="hashKeySerializer" ref="stringRedisSerializer" />
</bean>
<!-- 配置key的序列化方式,使用String类型进行序列化 -->
<bean id="stringRedisSerializer"
class="com.bigname.common.utils.FastJsonRedisSerializer" />
<!-- 配置hashValue的序列化方式,使用Jackson serializer,将hashValue以json串的形式存储到redis中 -->
<bean id="genericJackson2JsonRedisSerializer"
class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer">
</bean>
<!-- 配置RedisCacheConfig -->
<bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg name="redisOperations" ref="redisTemplate" />
<property name="defaultExpiration" value="${redis.expiration}" />
</bean>
<!-- 配置RedisCacheConfig -->
<bean id="redisCacheConfig" class="com.bigname.common.utils.RedisCacheConfig">
<constructor-arg ref="jedisConnectionFactory" />
<constructor-arg ref="redisTemplate" />
<constructor-arg ref="redisCacheManager" />
</bean>
</beans>
4.FastJsonRedisSerializer
package com.bigname.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.util.Assert;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
public class FastJsonRedisSerializer implements RedisSerializer<Object>{
private final Charset charset;
private final String target = "\"";
private final String replacement = "";
public FastJsonRedisSerializer() {
this(Charset.forName("UTF8"));
}
public FastJsonRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
@Override
public String deserialize(byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
@Override
public byte[] serialize(Object object) {
String string = JSON.toJSONString(object);
if (string == null) {
return null;
}
string = string.replace(target, replacement);
return string.getBytes(charset);
}
}
5.RedisCacheConfig
package com.bigname.common.utils;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport{
private volatile JedisConnectionFactory jedisConnectionFactory;
private volatile RedisTemplate<String, String> redisTemplate;
private volatile RedisCacheManager redisCacheManager;
public RedisCacheConfig() {
super();
}
/**
* 带参数的构造方法 初始化所有的成员变量
*
* @param jedisConnectionFactory
* @param redisTemplate
* @param redisCacheManager
*/
public RedisCacheConfig(JedisConnectionFactory jedisConnectionFactory, RedisTemplate<String, String> redisTemplate,
RedisCacheManager redisCacheManager) {
this.jedisConnectionFactory = jedisConnectionFactory;
this.redisTemplate = redisTemplate;
this.redisCacheManager = redisCacheManager;
}
public JedisConnectionFactory getJedisConnecionFactory() {
return jedisConnectionFactory;
}
public RedisTemplate<String, String> getRedisTemplate() {
return redisTemplate;
}
public RedisCacheManager getRedisCacheManager() {
return redisCacheManager;
}
@Bean
public KeyGenerator customKeyGenerator() {
return new KeyGenerator() {
public Object generate(Object target, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
6.实体类
package com.bigname.demo.entity;
import java.io.Serializable;
import com.bigname.common.BaseModel;
public class User extends BaseModel implements Serializable{
/**
*
*/
private static final long serialVersionUID = -9187083138474340478L;
private String userName;
private String password;
private Integer age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
7.dao
package com.bigname.demo.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.bigname.demo.entity.User;
public interface UserDao {
User selectUser(@Param("userName")String name,@Param("passWord")String password);
int register(User user);
String selectByUserName(String name);
List queryAll();
String selectUserqw();
}
8.UserServiceImpl
package com.bigname.demo.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.bigname.demo.dao.UserDao;
import com.bigname.demo.entity.User;
import com.bigname.demo.service.UserService;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userdao;
public User selectUser(String userName,String password) {
// TODO Auto-generated method stub
return userdao.selectUser(userName,password);
}
//@Cacheable("getUserById")
//标注该方法查询的结果进入缓存,再次访问时直接读取缓存中的数据
@CacheEvict(value="getUserById",allEntries=true)
public int insertUser(User user) {
// TODO Auto-generated method stub
return userdao.register(user);
}
public String selectByUserName(String name) {
// TODO Auto-generated method stub
return userdao.selectByUserName(name);
}
//标注该方法查询的结果进入缓存,再次访问时直接读取缓存中的数据
@Cacheable("queryUserAlls")
public List<User> queryUserAll() {
// TODO Auto-generated method stub
return userdao.queryAll();
}
public String selectUserqw() {
// TODO Auto-generated method stub
return userdao.selectUserqw();
}
}
9.controller
@RequestMapping(value = "/sys/ls")
@ResponseBody
public Object demo1(User users,HttpSession session,HttpServletRequest request){
String list = userservice.selectUserqw();
return list;
}
心得:研究了两天左右,网上又得说法都太离谱了。我这个目前解决了序列化和反序列化的问题,但是还有一个问题就是当一个service出现两个@Cacheable 就可能会失效 也就是说 另外一个@Cacheable也会进入之前的缓存 或者不起作用,这个还在研究,个人能力有限,还望大牛指导,欢迎评论