在spring中实现分布式 session管理
本文主要是在spring中实现分布式session,采用redis对session进行持久化管理,这样当应用部署的时候,不需要在resin、tomcat等容器里面进行分布式配置,方便加入新的节点服务器进行集群扩容,session不依赖各节点的服务器,可直接从redis获取。下面是功能的核心代码:
一、首先在web.xml里面配置
加入拦截器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<!-- 分布式session start -->
<filter>
<filter-name>distributedsessionfilter</filter-name>
<filter- class >distributedsessionfilter</filter- class >
<init-param>
<!-- 必填,密钥. 2 种方式, 1 对应为bean,格式为bean:key。 2 字符串,格式如:afffrfgv-->
<param-name>key</param-name>
<param-value>xxxxxxxx</param-value>
</init-param>
<init-param>
<!-- 必填,redis对应的bean,格式为bean:xx-->
<param-name>cachebean</param-name>
<param-value>bean:redispersistent</param-value> //distributedbaseinterface,对应于此接口,进行session的持久化操作
</init-param>
<init-param>
<!-- 必填, -->
<param-name>cookiename</param-name>
<param-value>testsessionid</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>distributedsessionfilter</filter-name>
<url-pattern>*. do </url-pattern>
</filter-mapping>
<!-- 分布式session end -->
|
二、拦截器的实现,核心代码如下
主要有以下的几个类:
- distributedsessionfilter,
- distributedsessionmanager,
- distributedhttpsessionwrapper,
- distributedhttpservletrequestwrapper
1、distributedsessionfilter实现filter:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import java.io.ioexception;
import java.util.hashmap;
import java.util.map;
import javax.servlet.filter;
import javax.servlet.filterchain;
import javax.servlet.filterconfig;
import javax.servlet.servletexception;
import javax.servlet.servletrequest;
import javax.servlet.servletresponse;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import org.springframework.web.context.webapplicationcontext;
import org.springframework.web.context.support.webapplicationcontextutils;
public class distributedsessionfilter implements filter {
private static final logger log = loggerfactory.getlogger(distributedsessionfilter. class );
private string cookiename;
//主要是对session进行管理的操作
private distributedsessionmanager distributedsessionmanager;
private string key;
}
|
容器启动时候的初始化方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@override
public void init(filterconfig config) throws servletexception {
webapplicationcontext wac = webapplicationcontextutils.getrequiredwebapplicationcontext(config
.getservletcontext());
string key = config.getinitparameter( "key" );
string cookiename = config.getinitparameter( "cookiename" );
string cachebean = config.getinitparameter( "cachebean" );
// 获取bean的名称,配置是"bean:"
string redisbeanstr = cachebean.substring( 5 );
distributedbaseinterface distributedcache = (distributedbaseinterface) wac.getbean(redisbeanstr);
// 获取key,有2种配置方式,1对应为bean,格式为bean:key。2字符串
if (key.startswith( "bean:" )) {
this .key = (string) wac.getbean(key.substring( 5 ));
} else {
this .key = key;
}
this .cookiename = cookiename;
this .distributedsessionmanager = distributedsessionmanager.getinstance(distributedcache);
//异常处理省略。。。
}
|
进行实际的请求拦截:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
@override
public void dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain)
throws servletexception, ioexception {
distributedhttpservletrequestwrapper distreq = null ;
try {
//请求处理
distreq = createdistributedrequest(servletrequest, servletresponse);
filterchain.dofilter(distreq, servletresponse);
} catch (throwable e) {
//省略。。。
} finally {
if (distreq != null ) {
try {
//处理完成request后,处理session(主要是保存session会话)
dealsessionafterrequest(distreq.getsession());
} catch (throwable e2) {
//省略。。。
}
}
}
}
//分布式请求
private distributedhttpservletrequestwrapper createdistributedrequest(servletrequest servletrequest,
servletresponse servletresponse) throws ioexception, servletexception {
httpservletrequest request = (httpservletrequest) servletrequest;
httpservletresponse response = (httpservletresponse) servletresponse;
string usersid = cookieutil.getcookie(cookiename, request);
string actualsid = distributedsessionmanager.getactualsid(usersid, request, key);
if (stringutil.isblank(actualsid)) {
if (stringutil.isnotblank(usersid)) {
log.info( "usersid[{}]验证不通过" , usersid);
}
// 写cookie
string[] usersidarr = distributedsessionmanager.createusersid(request, key);
usersid = usersidarr[ 0 ];
cookieutil.setcookie(cookiename, usersid, request, response);
actualsid = usersidarr[ 1 ];
}
actualsid = "sid:" + actualsid;
distributedhttpsessionwrapper distsession = null ;
try {
map<string, object> allattribute = distributedsessionmanager.getsession(actualsid, request.getsession()
.getmaxinactiveinterval());
distsession = new distributedhttpsessionwrapper(actualsid, request.getsession(), allattribute);
} catch (throwable e) {
// 出错,删掉缓存数据
log.error(e.getmessage(), e);
map<string, object> allattribute = new hashmap<string, object>();
distsession = new distributedhttpsessionwrapper(actualsid, request.getsession(), allattribute);
distributedsessionmanager.removesession(distsession);
}
distributedhttpservletrequestwrapper requestwrapper = new distributedhttpservletrequestwrapper(request,
distsession);
return requestwrapper;
}
// request处理完时操作session
private void dealsessionafterrequest(distributedhttpsessionwrapper session) {
if (session == null ) {
return ;
}
if (session.changed) {
distributedsessionmanager.savesession(session);
} else if (session.invalidated) {
distributedsessionmanager.removesession(session);
} else {
distributedsessionmanager.expire(session);
}
}
|
2、distributedsessionmanager,主要处理分布式session,核心代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
class distributedsessionmanager {
protected static final logger log = loggerfactory.getlogger(distributedsessionmanager. class );
private static distributedsessionmanager instance = null ;
//redis处理session的接口,自己根据情况实现
private distributedbaseinterface distributedbaseinterface;
private static byte [] lock = new byte [ 1 ];
private distributedsessionmanager(distributedbaseinterface distributedbaseinterface) {
this .distributedbaseinterface = distributedbaseinterface;
}
public static distributedsessionmanager getinstance(distributedbaseinterface redis) {
if (instance == null ) {
synchronized (lock) {
if (instance == null ) {
instance = new distributedsessionmanager(redis);
}
}
}
return instance;
}
//获取session
public map<string, object> getsession(string sid, int second) {
string json = this .distributedbaseinterface.get(sid,second);
if (stringutil.isnotblank(json)) {
return jsonutil.unserializemap(json);
}
return new hashmap<string, object>( 1 );
}
//保存session
public void savesession(distributedhttpsessionwrapper session) {
map<string, object> map=session.allattribute;
if (maputil.isempty(map)){
return ;
}
string json = jsonutil.serializemap(map);
this .distributedbaseinterface.set(session.getid(), json, session.getmaxinactiveinterval());
}
//删除session
public void removesession(distributedhttpsessionwrapper session) {
distributedbaseinterface.del(session.getid());
}
public void expire(distributedhttpsessionwrapper session) {
distributedbaseinterface.expire(session.getid(), session.getmaxinactiveinterval());
}
/**
* 创建cookie的sid
*/
public string[] createusersid(httpservletrequest request, string key) {
//...
}
public string getactualsid(string usersid, httpservletrequest request, string key) {
//...
}
}
|
3、distributedhttpsessionwrapper 实现了 httpsession,进行分布式session包装,核心代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
public class distributedhttpsessionwrapper implements httpsession {
private httpsession orgisession;
private string sid;
boolean changed = false ;
boolean invalidated = false ;
map<string, object> allattribute;
public distributedhttpsessionwrapper(string sid, httpsession session, map<string, object> allattribute) {
this .orgisession = session;
this .sid = sid;
this .allattribute = allattribute;
}
@override
public string getid() {
return this .sid;
}
@override
public void setattribute(string name, object value) {
changed = true ;
allattribute.put(name, value);
}
@override
public object getattribute(string name) {
return allattribute.get(name);
}
@override
public enumeration<string> getattributenames() {
set<string> set = allattribute.keyset();
iterator<string> iterator = set.iterator();
return new myenumeration<string>(iterator);
}
private class myenumeration<t> implements enumeration<t> {
iterator<t> iterator;
public myenumeration(iterator<t> iterator) {
super ();
this .iterator = iterator;
}
@override
public boolean hasmoreelements() {
return iterator.hasnext();
}
@override
public t nextelement() {
return iterator.next();
}
}
@override
public void invalidate() {
this .invalidated = true ;
}
@override
public void removeattribute(string name) {
changed = true ;
allattribute.remove(name);
}
@override
public long getcreationtime() {
return orgisession.getcreationtime();
}
@override
public long getlastaccessedtime() {
return orgisession.getlastaccessedtime();
}
@override
public int getmaxinactiveinterval() {
return orgisession.getmaxinactiveinterval();
}
@override
public servletcontext getservletcontext() {
return orgisession.getservletcontext();
}
@override
public object getvalue(string arg0) {
return orgisession.getvalue(arg0);
}
@override
public string[] getvaluenames() {
return orgisession.getvaluenames();
}
@override
public boolean isnew() {
return orgisession.isnew();
}
@override
public void putvalue(string arg0, object arg1) {
orgisession.putvalue(arg0, arg1);
}
@override
public void removevalue(string arg0) {
orgisession.removevalue(arg0);
}
@override
public void setmaxinactiveinterval( int arg0) {
orgisession.setmaxinactiveinterval(arg0);
}
@override
public httpsessioncontext getsessioncontext() {
return orgisession.getsessioncontext();
}
|
4、distributedhttpservletrequestwrapper 实现了 httpservletrequestwrapper,包装处理过的session和原始request,核心代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public class distributedhttpservletrequestwrapper extends javax.servlet.http.httpservletrequestwrapper {
private httpservletrequest orgirequest;
private distributedhttpsessionwrapper session;
public distributedhttpservletrequestwrapper(httpservletrequest request, distributedhttpsessionwrapper session) {
super (request);
if (session == null ){
//异常处理。。
}
if (request == null ){
//异常处理。。
}
this .orgirequest = request;
this .session = session;
}
public distributedhttpsessionwrapper getsession( boolean create) {
orgirequest.getsession(create);
return session;
}
public distributedhttpsessionwrapper getsession() {
return session;
}
}
|
5、另外,定义distributedbaseinterface接口,用来处理session入redis进行持久化操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public interface distributedbaseinterface {
/**
* 根据key获取缓存数据
* @param key
* @param seconds
*/
public string get(string key, int seconds);
/**
* 更新缓存数据
* @param key
* @param json
* @param seconds
*/
public void set(string key, string json, int seconds);
/**
* 删除缓存
* @param key
*/
public void del(string key);
/**
* 设置过期数据
* @param key
* @param seconds
*/
public void expire(string key, int seconds);
|
注:本文只是在spring中采用redis的方式对session进行管理,还有其他诸多的实现方式,比如在容器里面配置等,设计路由算法让session依赖于集群中的各个节点服务器,,,,,,但redis这种方式在实际应用中还是比较广泛的,lz公司主要就是采用此方式。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/u014263388/article/details/56020889