玖叶教程网

前端编程开发入门

基于redis实现session共享(redis实现session共享原理)

最近在自研框架里加入了session共享的实现,现在和大家分享下

session共享:

传统的单机服务器session由服务端生成并保存,那么在分布式场景下,session如何共享?

一般有两种方案:

1,集中式存储session。原理就是利用redis,memcache等统一存储。2,是在各服务器之间进行session复制。

我这里选择使用redis实现session共享。

具体步骤:

1,新增一个filter,进行session相关校验

2,实现HttpSession接口,改写getSession方法,从redis进行存取

3,生产新session后,将新session写到cookie中

简要代码:

1,web.xml配置filter

<!-- 集群session配置-基于缓存实现 -->

<filter>

<filter-name>ClusterSessionFilter</filter-name>

<filter-class>com.xxx.session.filter.ClusterSessionFilter</filter-class>

<init-param>

<param-name>sessionServiceId</param-name>

<param-value>sessionService</param-value>

</init-param>

<init-param>

<param-name>sessionKey</param-name>

<param-value>${server.name}_sessionKey</param-value>

</init-param>

<!-- <init-param>

<param-name>requestUriIgnorePattern</param-name>

<param-value>.*\.(png|gif|jpg|css|js|ico|jpeg|htm|html)lt;/param-value>

</init-param> -->

</filter>

<filter-mapping>

<filter-name>ClusterSessionFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

2,ClusterSessionFilter简要实现

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)

throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) servletRequest;

HttpServletResponse response = (HttpServletResponse) servletResponse;

//提出特殊连接的过滤

String requestUrl = request.getRequestURI();

if (this.requestUriIgnorePattern.matcher(requestUrl).matches()) {

chain.doFilter(servletRequest, servletResponse);

return;

}

Cookie cookies[] = request.getCookies();

String sid = "";

//从cookie中拿出sessionid

if (cookies != null) {

for (int i = 0; i < cookies.length; i++) {

Cookie cookie = cookies[i];

if (cookie.getName().equals(sessionKey)) {

sid = cookie.getValue();

break;

}

}

}

// 这一段校验拿到的sessionid,不是重点

String ip = IpUtil.getIpAddress(request);

int ipHash = ip.hashCode();

String sessionId = generateSessionString(ipHash);

if (StringUtils.isBlank(sid)) {

resetSessionIdValueInCookie(response, sessionId);

sid = sessionId;

}else{//判断是否伪造session

String[] sessionIdArr = sid.split("!");

if(sessionIdArr != null && sessionIdArr.length == 2){

if(!StringUtils.equals(String.valueOf(ipHash), sessionIdArr[1])){

resetSessionIdValueInCookie(response, sessionId);

sid = sessionId;

}

}

}

ClusterHttpServletRequestWrapper clusterHttpServletRequest = new ClusterHttpServletRequestWrapper(servletContext,request, sid, this.sessionService);

// 调用下个过滤器

// 这里是重点,往下调用时,我已经将request换成我的包装类了

// 下面重点看这个包装类

chain.doFilter(clusterHttpServletRequest, servletResponse);

//更新session的活动时间

ClusterHttpSessionWrapper clusterHttpSessionWrapper = (ClusterHttpSessionWrapper) clusterHttpServletRequest.getSession();

if(clusterHttpSessionWrapper != null){

clusterHttpSessionWrapper.saveSession();

}

}

4,对getSession的重写

public class ClusterHttpServletRequestWrapper extends HttpServletRequestWrapper {

private SessionManager sessionService;

private String sessionId;

private HttpSession httpSession;

private ServletContext servletContext;

public ClusterHttpServletRequestWrapper(ServletContext servletContext, HttpServletRequest request, String sessionId, SessionManager sessionService) {

super(request);

this.sessionId = sessionId;

this.sessionService = sessionService;

this.servletContext = servletContext;

}

@Override

public HttpSession getSession(boolean create) {

if(this.httpSession == null){

this.httpSession = new ClusterHttpSessionWrapper(this.sessionId, servletContext, this.sessionService);

}

return this.httpSession;

}

@Override

public HttpSession getSession() {

return getSession(false);

}

}

ClusterHttpSessionWrapper 实现HttpSession接口

public class ClusterHttpSessionWrapper implements HttpSession{

private SessionManager sessionService;

private Map<Object,Object> map;

private String sessionId;

private long creationTime;

private long lastAccessedTime;

private int maxInactiveInterval;

private ServletContext servletContext;

private boolean isNew = false;

/**

* 标志位,是否对session中的信息作了更新操作

*/

private boolean changed;

public ClusterHttpSessionWrapper(String sessionId,ServletContext servletContext,SessionManager sessionService) {

this.sessionId = sessionId;

this.sessionService = sessionService;

this.map = this.sessionService.getSession(sessionId);

this.creationTime = (Long)this.map.get("_SESSION_CREATE_TIME_");

this.lastAccessedTime = System.currentTimeMillis();

this.servletContext = servletContext;

this.isNew = true;

}

@Override

public Object getAttribute(String key) {

resetLastAccessTime();

return this.map.get(key);

}

@Override

public Enumeration<Object> getAttributeNames() {

resetLastAccessTime();

return Collections.enumeration(this.map.keySet());

}

@Override

public void invalidate() {

resetLastAccessTime();

this.map.clear();

this.map.put("_SESSION_CREATE_TIME_", System.currentTimeMillis());

this.changed = true;

this.sessionService.removeSession(this.sessionId);

}

@Override

public void removeAttribute(String key) {

resetLastAccessTime();

this.map.remove(key);

this.changed = true;

}

@Override

public void setAttribute(String key, Object value) {

resetLastAccessTime();

this.map.put(key, value);

this.changed = true;

}

@Override

public String getId() {

return this.sessionId;

}

public void saveSession(){

if(this.changed){

this.sessionService.updateSession(this.sessionId, this.map);

}

}

@Override

public long getCreationTime() {

return creationTime;

}

@Override

public long getLastAccessedTime() {

return lastAccessedTime;

}

private void resetLastAccessTime(){

this.lastAccessedTime = System.currentTimeMillis();

this.map.put("_SESSION_CREATE_TIME_", this.lastAccessedTime);

}

@Override

public void setMaxInactiveInterval(int interval) {

this.maxInactiveInterval = interval;

}

@Override

public int getMaxInactiveInterval() {

return this.maxInactiveInterval;

}

@Override

public ServletContext getServletContext() {

return this.servletContext;

}

@Override

public HttpSessionContext getSessionContext() {

throw new UnsupportedOperationException("该方法不被支持调用");

}

@Override

public Object getValue(String name) {

return getAttribute(name);

}

@Override

public String[] getValueNames() {

throw new UnsupportedOperationException("该方法不被支持调用");

}

@Override

public void putValue(String name, Object value) {

setAttribute(name, value);

}

@Override

public void removeValue(String name) {

removeAttribute(name);

}

@Override

public boolean isNew() {

return isNew;

}

}

5,sessionService的实现,就是对redis的操作

public class SessionManagerRedisImpl implements SessionManager {

private JedisCluster jedisCluster;

//second

private Integer expireTime;

public void setJedisCluster(JedisCluster jedisCluster) {

this.jedisCluster = jedisCluster;

}

public void setExpireTime(Integer expireTime) {

this.expireTime = expireTime;

}

@Override

public Map<Object, Object> getSession(String sessionId) {

Map<byte[],byte[]> map = jedisCluster.hgetAll(sessionId.getBytes());

Map<Object,Object> session = new HashMap<Object,Object>();

if (map == null || map.size() == 0) {

session.put("_SESSION_CREATE_TIME_", System.currentTimeMillis());//session创建时间

addSession(sessionId,session);

return session;

}

Set<Map.Entry<byte[],byte[]>> set = map.entrySet();

Iterator<Map.Entry<byte[],byte[]>> it = set.iterator();

while (it.hasNext()){

Map.Entry<byte[],byte[]> entry = it.next();

session.put(SerializeUtil.unserialize(entry.getKey()),SerializeUtil.unserialize(entry.getValue()));

}

//update session expire time

jedisCluster.expire(sessionId.getBytes(),expireTime);

return session;

}

@Override

public void updateSession(String id, Map<Object, Object> session) {

if (StringUtils.isBlank(id) || session == null){

return;

}

Set<Map.Entry<Object, Object>> set = session.entrySet();

Iterator<Map.Entry<Object, Object>> it = set.iterator();

while (it.hasNext()){

Map.Entry<Object, Object> entry = it.next();

jedisCluster.hset(id.getBytes(), SerializeUtil.serialize(entry.getKey()),SerializeUtil.serialize(entry.getValue()));

}

jedisCluster.expire(id.getBytes(),expireTime);

}

@Override

public void removeSession(String id) {

if (StringUtils.isBlank(id)){

return;

}

jedisCluster.del(id.getBytes());

}

@Override

public void addSession(String id, Map<Object, Object> session) {

updateSession(id,session);

}

}

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言