SpringMVC整合Redis的一点问题

自己的项目不敢用公司的redis,只好用java原生的方法,做了一个序列化和反序列化,加了一个简单的泛型,可以实现redis缓存java原生对象了。中间还出现了一个比较奇怪的错误。

上周周末的时候我提交了代码,一切OK,这周周一来的时候,重新跑了一次,出现了空指针

//redisService里面的代码
    @Autowired
    private JedisSingleFactory jedisSingleFactory;
    private Jedis jedis=jedisSingleFactory.getResource();

理论上,这样写,java是要按照从上到下的顺序加载的,也就是说,jedisSingleFactory不可能在还是空的情况下,就被调用getResource方法,来生成jedis。不幸的是,这件事确实发生了,而且由于上周还可以跑通,所以我有道理相信这个加载顺序是不稳定的。本来想在jedisSingleFactory前面加上static,保证加载顺序,可静态成员变量貌似又不能被set,也就不能被spring注入,只好用下面这种方法了

//每个用到jedis链接的地方,都调用该方法,该方法会调用
//jedisSingleFactory(jedisSingleFactory.getJedis()里面是一个单例模式)
  public Jedis getJedis() {
        if(jedis==null){
            jedis=jedisSingleFactory.getJedis();
        }
        return jedis;
    }

解决这个问题,下面就是序列化的事情了,其实也蛮简单的

 @Override
    public <T> boolean set(String key, T value, int liveTime) {
        boolean isGood = true;
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        byte[] bytes = null;
        if (value != null) {
            try {
                baos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(baos);
                oos.writeObject(value);
                bytes = baos.toByteArray();
                this.getJedis().setex(key.getBytes(), liveTime, bytes);
            } catch (Exception e) {
                logger.error("序列化对象:{} 出错:{}", value, e.getMessage());
                isGood = false;
            }
        }
        return isGood;
    }
    @Override
    public <T> T get(String key) {
        ByteArrayInputStream bais = null;
        T object = null;
        byte[] bytes=this.getJedis().get(key.getBytes());
        if(bytes!=null&&bytes.length>0){
            bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(bais);
                object = (T) ois.readObject();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("反序列化对象:{} 出错:{}", key, e.getMessage());
            }catch (ClassNotFoundException e){
                logger.error("反序列化对象:{} 出错:{}", key, e.getMessage());
            }finally {
                return null;//鸡肋一下
            }
        }
        return object;
    }

还有就是意识到,在mock数据的时候(主要是在单元测试里面),context.xml里面,需要手动import servlet.xml,不然找不到,因为它本身没有web.xml配置servle的选项。

至于redis的依赖

       <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.5.0.RELEASE</version>
        </dependency>

context.xml配置

   <context:property-placeholder location="classpath:redis.properties" />
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxTotal" value="${redis.maxTotal}" />
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>

    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:hostName="${redis.host}"
          p:port="${redis.port}"
          p:password="${redis.pass}"
          p:poolConfig-ref="poolConfig"/>

    <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory"   ref="connectionFactory" />
    </bean>

    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
        <constructor-arg name="host" value="localhost"></constructor-arg>
    </bean>

    <bean id="jedisSingleFactory" class="com.liushuqing.wechat.web.jedis.JedisSingleFactory">
        <property name="jedisPool" ref="jedisPool"/>
    </bean>

大概就酱紫~其实redisTemplate是不需要配置的,因为我已经手动实现了一个jedis的序列化~ redis的配置是我抄的别人的。。。

\# Redis settings
\#redis的服务器地址
redis.host=localhost  
\#redis的服务端口
redis.port=6379  
\#密码
redis.pass=**  
\#链接数据库
redis.default.db= 0  
\#客户端超时时间单位是毫秒
redis.timeout=100000  
\#最大连接数
redis.maxTotal=300  
\#最大空闲数
redis.maxIdle=100  
\#最大建立连接等待时间
redis.maxWaitMillis=1000  
\#指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
redis.testOnBorrow=true  

写一个单元测试跑一下

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:test-context.xml")
public class SpringRedisTest{  
    private static final Logger logger= LoggerFactory.getLogger(SpringRedisTest.class);
    @Autowired
    RedisService redisService;
    @Test
    public void 测试对象(){
        SearchTask searchTask=new SearchTask();
        searchTask.setCreateTime(new Date());
        searchTask.setFinishTime(new Date());
        searchTask.setName("hahahahhaNiha");
        String name="Object";
        redisService.set(name,searchTask);
        SearchTask task= redisService.get(name);
        logger.debug("拿到一个对象{},应该是对的!",task.toString());
    }
}

一切OK了~

刘摸鱼

退堂鼓表演艺术家

杭州