在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