在spring 里面,spring-session 和 spring-session-data-redis 结合让项目平滑升级与redis 缓存的一些运用

之前每次升级的时候,还要停集群节点,然后升级以后再启动,需求需要不停机升级! 然后实现是用springsession 结合redis 做的缓存!

引入jar

  <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session</artifactId>
            <version>1.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>1.2.2.RELEASE</version>
        </dependency>
         <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.7.1.RELEASE</version>

        </dependency>

注意: 如果spring 版本不高!而redis 和session版本高的话 会导致冲突



<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">
		<!--session过滤器 -->
	 <filter>
		<filter-name>springSessionRepositoryFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 </filter>  
	
	<filter-mapping>
		<filter-name>springSessionRepositoryFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<servlet>
		<servlet-name>FileUploadServlet</servlet-name>
		<servlet-class>com.tianyi.bph.cg.web.controller.basicdata.FileUploadServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>FileUploadServlet</servlet-name>
		<url-pattern>/servlet/FileUploadServlet</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>ExcelImportServlet</servlet-name>
		<servlet-class>com.tianyi.bph.cg.web.controller.basicdata.ExcelImportServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>ExcelImportServlet</servlet-name>
		<url-pattern>/servlet/ExcelImportServlet</url-pattern>
	</servlet-mapping>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:spring/applicationContext*.xml
		</param-value>
	</context-param>
	<context-param>
		<param-name>spring.profiles.active</param-name>
		<param-value>development</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
	</listener>

	<!-- 配置druid 监控页面 内置监控页面的首页是/druid/index.html -->
	<servlet>
		<servlet-name>DruidStatView</servlet-name>
		<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>DruidStatView</servlet-name>
		<url-pattern>/druid/*</url-pattern>
	</servlet-mapping>

	<!--为了得到系统路径 -->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- <servlet-class>com.tianyi.bph.MainServlet</servlet-class> -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/dispatcher-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>*.action</url-pattern>
	</servlet-mapping>

	<!-- spring自带字符拦击过滤器进行拦截设置编码 -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>utf8</param-value>
		</init-param>
	</filter>
	<filter>
		<filter-name>SessionInvalidate</filter-name>
		<filter-class>com.tianyi.bph.cg.rest.Filterlogin</filter-class>
		<init-param>
			<param-name>redirectURL</param-name>
			<param-value>/cg/login.jsp</param-value>
		</init-param>
		<init-param>
			<param-name>notCheckURLList</param-name>
			<param-value>/cg/login.jsp,/admin/help/</param-value>
		</init-param>
		
	</filter>
	<!--过滤/jsp文件夹下所有jsp -->
	<filter-mapping>
		<filter-name>SessionInvalidate</filter-name>
		<url-pattern>*.jsp</url-pattern>
	</filter-mapping>

	<filter>
		<filter-name>sitemesh</filter-name>
		<filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>*.action</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>sitemesh</filter-name>
		<url-pattern>*.action</url-pattern>
	</filter-mapping>

	<!-- druid监控Filter配置 -->
	<filter>
		<filter-name>DruidWebStatFilter</filter-name>
		<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
		<init-param>
			<param-name>exclusions</param-name>
			<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>DruidWebStatFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>




	<welcome-file-list>
		<welcome-file>/cg/login.jsp</welcome-file>
	</welcome-file-list>
	<session-config>
		<session-timeout>-1</session-timeout>
	</session-config>
	<error-page>
		<error-code>404</error-code>
		<location>/404.jsp</location>
	</error-page>
	<error-page>
		<error-code>500</error-code>
		<location>/500.jsp</location>
	</error-page>

</web-app>

配置拦截器!  注意springsession 的拦截器必须放到第一个位置,不然会有奇怪的事情发生!

#redis ��Ⱥ���� host:post,host:post
#reidsClusterNodes=xxx.xxx.xx.xx:xxx 多节点集群
#redis �������� host:post

reidsClusterNodes=xxx.xxx.xx.xx:xxx 单节点

配置redis !

package com.tianyi.bph.cg.web.cache;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * Created by fan on 2017/11/14.
 */
@Component
@PropertySource(value = "classpath:parameter.properties")
public class ClusterConfigurationProperties {

   
	@Value("#{config[reidsClusterNodes]}")
     private String  nodes;

	public String getNodes() {
		return nodes;
	}

	public void setNodes(String nodes) {
		this.nodes = nodes;
	}

    public List<String> getNodesByno(){
    	String[] node = nodes.split(",");
    	List<String> nodes = Arrays.asList(node);
		return nodes;
    }
    
}

spring读取配置redis 信息!

package com.tianyi.bph.cg.web.cache;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
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.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashSet;
import java.util.Set;


/**
 * RedisHttpSessionConfiguration的配置文件
 *
 * 引入RedisHttpSessionConfiguration.class
 *
 * maxInactiveIntervalInSeconds设置session在redis里的超时
 *
 * @author fan
 * 
 */
@EnableRedisHttpSession(maxInactiveIntervalInSeconds=36000)
public class SessionConfig {

	 @Autowired
	 private ClusterConfigurationProperties clusterProperties;	
	 final static Logger logger = LoggerFactory.getLogger(SessionConfig.class);	
	
	 
	
	  @Bean  
      public static ConfigureRedisAction configureRedisAction() {  
          return ConfigureRedisAction.NO_OP;  
      }


	  
    @Bean(name="jedisconnectionFactory")
    public JedisConnectionFactory jedisconnectionFactory() {
    	 try {
             if (StringUtils.isEmpty(clusterProperties.getNodes())) {
                 logger.error("not set redis node");
                 return null;
             }
             if (clusterProperties.getNodesByno().size() > 1) {
                 logger.info("redis sever enable cluster model");
                 RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(
                         clusterProperties.getNodesByno());
                 JedisConnectionFactory connectionFactory = new JedisConnectionFactory(clusterConfiguration,poolConfig());
                 connectionFactory.setTimeout(3600);
                 return connectionFactory;
             } else {          	 
            		 logger.info("redis sever enable single model");
                     JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig());
                     String redisUrl = clusterProperties.getNodesByno().get(0);
                     jedisConnectionFactory.setPort(Integer.parseInt(redisUrl.split(":")[1]));
                     jedisConnectionFactory.setHostName(redisUrl.split(":")[0]);
                     jedisConnectionFactory.setTimeout(3600);
                try {
                     return jedisConnectionFactory;
				} catch (Exception e) {
					 logger.error("redis connection error");
				}
                 
             }
         } catch (Exception e) {
             logger.error("redis connection error");
         }
         return null;
    }
    

    /**
     * JedisPoolConfig 配置
     *
     * 配置JedisPoolConfig的各项属性
     *
     * @return
     */
    private JedisPoolConfig poolConfig(){
        JedisPoolConfig jedisPoolConfig= new JedisPoolConfig();
        //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
        jedisPoolConfig.setBlockWhenExhausted(true);
        
        //是否启用pool的jmx管理功能, 默认true
        jedisPoolConfig.setJmxEnabled(true);
        
        //jedis调用returnObject方法时,是否进行有效检查
        jedisPoolConfig.setTestOnReturn(true);
        
        //最大空闲连接数, 默认8个
        jedisPoolConfig.setMaxIdle(8);
        
        //最大连接数, 默认8个
        jedisPoolConfig.setMaxTotal(8);
        
        //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
        jedisPoolConfig.setMaxWaitMillis(-1);
        
        //逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
        jedisPoolConfig.setMinEvictableIdleTimeMillis(1800000);
        
        //最小空闲连接数, 默认0
        jedisPoolConfig.setMinIdle(0);
        
        //每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
        jedisPoolConfig.setNumTestsPerEvictionRun(3);
        
        //对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断  (默认逐出策略)  
        jedisPoolConfig.setSoftMinEvictableIdleTimeMillis(1800000);
        
        //在获取连接的时候检查有效性, 默认false
        jedisPoolConfig.setTestOnBorrow(false);
        
        //在空闲时检查有效性, 默认false
        jedisPoolConfig.setTestWhileIdle(false);
        
        //逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(-1);

        return jedisPoolConfig;
    }



    /**
     * RedisTemplate配置
     *
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, String> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
                Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);// 如果key是String
        // 需要配置一下StringSerializer,不然key会乱码
        // /XX/XX
        template.afterPropertiesSet();
        return template;
    }
    /**
     * 管理缓存
     *
     * @param redisTemplate
     * @return
     */
       @SuppressWarnings("rawtypes")
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        CustomRedisCacheManager cacheManager = new CustomRedisCacheManager(
                redisTemplate);
        // rcm.setCacheNames(cacheNames)
        // 设置缓存过期时间
        // rcm.setDefaultExpiration(60);//秒
        // 设置value的过期时间
        Map<String, Long> expiresMap = new ConcurrentHashMap<String, Long>();
        // map.put("test", 60L);
        Set<String> cacheNames = new HashSet<>();
        cacheNames.add("device-data");
        cacheNames.add("alarm-event-data");
        cacheNames.add("gps-data");
        cacheNames.add("alarm-event-new-data");
        cacheNames.add("relation-organ-data");
        cacheNames.add("relation-police-data");
        cacheNames.add("platform-config-data");
        cacheNames.add("organ-data");
        cacheNames.add("intercom-platform-data");
        cacheNames.add("alarm-seat-data");
        expiresMap.put(
                "alarm-seat-data",
                Long.parseLong(systemConfigRepository.findByKey(
                        "expires_alarm-seat-data").getValue()));

        expiresMap.put("alarm-event-new-data", 120L);
        // 设置 by chen
        cacheNames.add("relation-organ-data-new");
        expiresMap.put("relation-organ-data-new", 600L);
        // end
        cacheManager.setCacheNames(cacheNames);
        cacheManager.setExpires(expiresMap);
        cacheManager.setUsePrefix(true);
        return cacheManager;
    }
    public static void main(String[] args) {  
        Jedis jedis = new Jedis("25.30.9.4",6379);  
        //ping通显示PONG  
        System.out.println(jedis.ping());//去ping我们redis的主机所在ip和端口  
    }

}

注入springsession bean 和 spring -session-redis 的配置 


package com.tianyi.bph.cg.web.cache;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.util.Assert;

/**
 * 
 * on 2017/11/28
 */
public class CustomRedisCacheManager extends RedisCacheManager {
    private static Logger logger = LoggerFactory.getLogger(CustomRedisCacheManager.class);

    public CustomRedisCacheManager(RedisOperations redisOperations) {
        super(redisOperations);
    }

    @Override
    public Cache getCache(String name) {
        return new CustomRedisCacheManager.RedisCacheWrapper(super.getCache(name));
    }

    protected static class RedisCacheWrapper implements Cache {

        private final Cache delegate;

        public RedisCacheWrapper(Cache redisCache) {
            Assert.notNull(redisCache, "delegate cache must not be null");
            this.delegate = redisCache;
        }

        @Override
        public String getName() {
            try {
                return delegate.getName();
            } catch (Exception e) {
                return handleException(e);
            }
        }

        @Override
        public Object getNativeCache() {
            try {
                return delegate.getNativeCache();
            } catch (Exception e) {
                return handleException(e);
            }
        }

        @Override
        public Cache.ValueWrapper get(Object key) {
            try {
                return delegate.get(key);
            } catch (Exception e) {
                return handleException(e);
            }
        }




        @Override
        public void put(Object key, Object value) {
            try {
                delegate.put(key, value);
            } catch (Exception e) {
                handleException(e);
            }
        }



        @Override
        public void evict(Object o) {
            try {
                delegate.evict(o);
            } catch (Exception e) {
                handleException(e);
            }
        }

        @Override
        public void clear() {
            try {
                delegate.clear();
            } catch (Exception e) {
                handleException(e);
            }
        }

        private <T> T handleException(Exception e) {
            logger.error("redis连接异常", e);
            return null;
        }
    }
}

redis 生成key 的规则代码!

  redis 的key 是随需要定义的

这个是springsession 自动生成 纪录每一个登录人信息


redis存入缓存  key 得 和 配置里面的一样


版权声明:本文为bianmadetangyuan原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。