之前每次升级的时候,还要停集群节点,然后升级以后再启动,需求需要不停机升级! 然后实现是用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 得 和 配置里面的一样