什么是redis:redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。(我也是百度的,个人理解reids就是个比较轻量级的key——value模式的
数据库,这个数据库的存储性能很好,可以用来代替缓存实现的很多功能。而且这个redis数据库是第三方独立的服务,可以用在负载均衡情况下多个服务器,多个web容器之间公用数据的缓存。) 要使用reids,首先可以到官网reids的jar包和redis。 然后把redis的jar包导入到项目中。
我用的版本是2.1.0. 系统是32位的,所以我解压了32位的redis服务。
打开以后使用里面的redis-servier。exe来启动redis服务。启动后的结果如下图所示
这里的redisManager是通过spring来进行管理的,所以直接使用了@value来读取properties文件中的属性。properties文件的内容如下:
ip定义为本机的ip,端口是redis默认的6379端口。
在spring中就是在这个地方把reids服务的配置文件redis.properties文件加载到spring中管理的。
这样redis服务就集成到了项目中,具体的使用,通过对shiro默认缓存和session数据的缓存的保存过程来展示。
项目中遇到的问题是这样的,在同时使用一个机器使用多个web容器或者多个机器同时来为一个项目进行负载均衡时,shiro的默认缓存和session数据无法在多个web容器或者多个机器之间进行同步。为了达到多web容器或多机器负载均衡的目的,我们修改了shiro的默认session管理器和缓存管理器来使shiro通过redis来管理session和缓存。这样多个web容器或机器之间的数据就可以互通共用了。 首先是shiro的配置文件,我用的是spring集成的方式。
主要看上图的红色部分:其中customShiroSessionDAO、jedisShiroSessionRepository用来处理session;customShiroCacheManager、jedisShiroCacheManager用来处理缓存。
他们的源代码如下:
这里我们是继承了shiro的AbstractSessionDAO,然后仿照shiro的模式,给他一个shiroSessionRepository,来进行详细的session存储操作。
具体的使用就如如上代码所示,为什么要弄一个什么ShiroCacheManager和ShiroSessionRepository接口呢,我想各位大侠也能知道的。有了这个两个接口,我们就可以通过这个两个接口来实现更多形式的shiro的session和缓存的管理了。
在很多地方使用到了SerializeUtils,它的作用就是把对象转化为byte数组,或把byte数组转化为对象。源代码如下:
然后项目的运行结果如下:
从图中可以看到,我登录后,session信息已经保存到了redis数据库中。多个tomcat做负载均衡的测试结果也很良好,但是我这个笔记本没有安装那种环境,所以无法测试。这都是个人一点小东西,各位大神勿喷。
打开以后使用里面的redis-servier。exe来启动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
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
|
package
org.calonlan.security.component;
import
java.util.Iterator;
import
java.util.Set;
import
org.springframework.beans.factory.annotation.Value;
import
redis.clients.jedis.Jedis;
import
redis.clients.jedis.JedisPool;
import
redis.clients.jedis.JedisPoolConfig;
/**
* @author Administrator
* redismanager主要用来给用户提供一个设计完备的,通过jedis的jar包来管理redis内存数据库的各种方法
*/
public
class
RedisManager {
// ip和port属性都定义在了properties文件中,这里通过spring的注解方式来直接使用
@Value
(
"${redis.ip}"
)
private
String host;
@Value
(
"${redis.port}"
)
private
int
port;
// 设置为0的话就是永远都不会过期
private
int
expire =
0
;
// 定义一个管理池,所有的redisManager共同使用。
private
static
JedisPool jedisPool =
null
;
public
RedisManager() {
}
/**
*
* 初始化方法,在这个方法中通过host和port来初始化jedispool。
*
* */
public
void
init() {
if
(
null
== host ||
0
== port) {
System.out.println(
"请初始化redis配置文件"
);
throw
new
NullPointerException(
"找不到redis配置"
);
}
if
(jedisPool ==
null
) {
jedisPool =
new
JedisPool(
new
JedisPoolConfig(), host, port);
}
}
/**
* get value from redis
*
* @param key
* @return
*/
public
byte
[] get(
byte
[] key) {
byte
[] value =
null
;
Jedis jedis = jedisPool.getResource();
try
{
value = jedis.get(key);
}
finally
{
jedisPool.returnResource(jedis);
}
return
value;
}
/**
* get value from redis
*
* @param key
* @return
*/
public
String get(String key) {
String value =
null
;
Jedis jedis = jedisPool.getResource();
try
{
value = jedis.get(key);
}
finally
{
jedisPool.returnResource(jedis);
}
return
value;
}
/**
* set
*
* @param key
* @param value
* @return
*/
public
byte
[] set(
byte
[] key,
byte
[] value) {
Jedis jedis = jedisPool.getResource();
try
{
jedis.set(key, value);
if
(
this
.expire !=
0
) {
jedis.expire(key,
this
.expire);
}
}
finally
{
jedisPool.returnResource(jedis);
}
return
value;
}
/**
* set
*
* @param key
* @param value
* @return
*/
public
String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
try
{
jedis.set(key, value);
if
(
this
.expire !=
0
) {
jedis.expire(key,
this
.expire);
}
}
finally
{
jedisPool.returnResource(jedis);
}
return
value;
}
/**
* set
*
* @param key
* @param value
* @param expire
* @return
*/
public
byte
[] set(
byte
[] key,
byte
[] value,
int
expire) {
Jedis jedis = jedisPool.getResource();
try
{
jedis.set(key, value);
if
(expire !=
0
) {
jedis.expire(key, expire);
}
}
finally
{
jedisPool.returnResource(jedis);
}
return
value;
}
/**
* set
*
* @param key
* @param value
* @param expire
* @return
*/
public
String set(String key, String value,
int
expire) {
Jedis jedis = jedisPool.getResource();
try
{
jedis.set(key, value);
if
(expire !=
0
) {
jedis.expire(key, expire);
}
}
finally
{
jedisPool.returnResource(jedis);
}
return
value;
}
/**
* del
*
* @param key
*/
public
void
del(
byte
[] key) {
Jedis jedis = jedisPool.getResource();
try
{
jedis.del(key);
}
finally
{
jedisPool.returnResource(jedis);
}
}
/**
* del
*
* @param key
*/
public
void
del(String key) {
Jedis jedis = jedisPool.getResource();
try
{
jedis.del(key);
}
finally
{
jedisPool.returnResource(jedis);
}
}
/**
* flush
*/
public
void
flushDB() {
Jedis jedis = jedisPool.getResource();
try
{
jedis.flushDB();
}
finally
{
jedisPool.returnResource(jedis);
}
}
/**
* size
*/
public
Long dbSize() {
Long dbSize = 0L;
Jedis jedis = jedisPool.getResource();
try
{
dbSize = jedis.dbSize();
}
finally
{
jedisPool.returnResource(jedis);
}
return
dbSize;
}
/**
* keys
*
* @param regex
* @return
*/
public
Set<
byte
[]> keys(String pattern) {
Set<
byte
[]> keys =
null
;
Jedis jedis = jedisPool.getResource();
try
{
keys = jedis.keys(pattern.getBytes());
}
finally
{
jedisPool.returnResource(jedis);
}
return
keys;
}
public
void
dels(String pattern) {
Set<
byte
[]> keys =
null
;
Jedis jedis = jedisPool.getResource();
try
{
keys = jedis.keys(pattern.getBytes());
Iterator<
byte
[]> ito = keys.iterator();
while
(ito.hasNext()) {
jedis.del(ito.next());
}
}
finally
{
jedisPool.returnResource(jedis);
}
}
public
String getHost() {
return
host;
}
public
void
setHost(String host) {
this
.host = host;
}
public
int
getPort() {
return
port;
}
public
void
setPort(
int
port) {
this
.port = port;
}
public
int
getExpire() {
return
expire;
}
public
void
setExpire(
int
expire) {
this
.expire = expire;
}
}
</
byte
[]></
byte
[]></
byte
[]></
byte
[]>
|
这里的redisManager是通过spring来进行管理的,所以直接使用了@value来读取properties文件中的属性。properties文件的内容如下:
1
2
|
<span style=
"white-space:pre"
> </span>redis.ip=
127.0
.
0.1
<span style=
"white-space:pre"
> </span> redis.port=
6379
|
ip定义为本机的ip,端口是redis默认的6379端口。
1
2
3
4
5
6
7
8
|
<bean
class
=
"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
id=
"propertyConfigurer"
>
<property name=
"locations"
>
<list>
<value>classpath:/config/jdbc.properties</value>
<value>classpath:/config/redis.properties</value>
</list>
</property>
</bean>
|
这样redis服务就集成到了项目中,具体的使用,通过对shiro默认缓存和session数据的缓存的保存过程来展示。
项目中遇到的问题是这样的,在同时使用一个机器使用多个web容器或者多个机器同时来为一个项目进行负载均衡时,shiro的默认缓存和session数据无法在多个web容器或者多个机器之间进行同步。为了达到多web容器或多机器负载均衡的目的,我们修改了shiro的默认session管理器和缓存管理器来使shiro通过redis来管理session和缓存。这样多个web容器或机器之间的数据就可以互通共用了。 首先是shiro的配置文件,我用的是spring集成的方式。
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
<beans
default
-lazy-init=
"false"
xmlns=
"http://www.springframework.org/schema/beans"
xmlns:aop=
"http://www.springframework.org/schema/aop"
xmlns:context=
"http://www.springframework.org/schema/context"
xmlns:jee=
"http://www.springframework.org/schema/jee"
xmlns:mvc=
"http://www.springframework.org/schema/mvc"
xmlns:p=
"http://www.springframework.org/schema/p"
xmlns:tx=
"http://www.springframework.org/schema/tx"
xmlns:util=
"http://www.springframework.org/schema/util"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemalocation="
http:
//www.springframework.org/schema/util
http:
//www.springframework.org/schema/util/spring-util-3.0.xsd
http:
//www.springframework.org/schema/beans
http:
//www.springframework.org/schema/beans/spring-beans-3.0.xsd
http:
//www.springframework.org/schema/context
http:
//www.springframework.org/schema/context/spring-context-3.0.xsd
http:
//www.springframework.org/schema/tx
http:
//www.springframework.org/schema/tx/spring-tx-3.0.xsd
http:
//www.springframework.org/schema/jee
http:
//www.springframework.org/schema/jee/spring-jee-3.0.xsd
http:
//www.springframework.org/schema/mvc
http:
//www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http:
//www.springframework.org/schema/aop
http:
//www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 缓存管理器 -->
<bean
class
=
"org.calonlan.security.spring.SpringCacheManagerWrapper"
id=
"cacheManager"
>
<property name=
"cacheManager"
ref=
"springCacheManager"
>
</property></bean>
<!-- 凭证匹配器 -->
<bean
class
=
"org.calonlan.security.credentials.RetryLimitHashedCredentialsMatcher"
id=
"credentialsMatcher"
>
<constructor-arg ref=
"cacheManager"
>
<property name=
"hashAlgorithmName"
value=
"md5"
>
<property name=
"hashIterations"
value=
"2"
>
<property name=
"storedCredentialsHexEncoded"
value=
"true"
>
</property></property></property></constructor-arg></bean>
<!-- Realm实现 -->
<bean
class
=
"org.calonlan.security.realm.UserRealm"
id=
"userRealm"
>
<property name=
"credentialsMatcher"
ref=
"credentialsMatcher"
>
<property name=
"cachingEnabled"
value=
"true"
>
<!--<property name=
"authenticationCachingEnabled"
value=
"true"
/> -->
<!--<property name=
"authenticationCacheName"
value=
"authenticationCache"
/> -->
<!--<property name=
"authorizationCachingEnabled"
value=
"true"
/> -->
<!--<property name=
"authorizationCacheName"
value=
"authorizationCache"
/> -->
</property></property></bean>
<!-- 会话ID生成器 -->
<bean
class
=
"org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"
id=
"sessionIdGenerator"
>
<!-- 会话Cookie模板 -->
<bean
class
=
"org.apache.shiro.web.servlet.SimpleCookie"
id=
"sessionIdCookie"
>
<constructor-arg value=
"sid"
>
<property name=
"httpOnly"
value=
"true"
>
<property name=
"maxAge"
value=
"-1"
>
</property></property></constructor-arg></bean>
<bean
class
=
"org.apache.shiro.web.servlet.SimpleCookie"
id=
"rememberMeCookie"
>
<constructor-arg value=
"rememberMe"
>
<property name=
"httpOnly"
value=
"true"
>
<property name=
"maxAge"
value=
"2592000"
><!--
30
天 -->
</property></property></constructor-arg></bean>
<!-- rememberMe管理器 -->
<bean
class
=
"org.apache.shiro.web.mgt.CookieRememberMeManager"
id=
"rememberMeManager"
>
<!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(
128
256
512
位) -->
<property name=
"cipherKey"
value=
"#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"
>
<property name=
"cookie"
ref=
"rememberMeCookie"
>
</property></property></bean>
<!-- 会话DAO -->
<bean
class
=
"org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"
id=
"sessionDAO"
>
<property name=
"activeSessionsCacheName"
value=
"shiro-activeSessionCache"
>
<property name=
"sessionIdGenerator"
ref=
"sessionIdGenerator"
>
</property></property></bean>
<!-- 会话验证调度器 -->
<bean
class
=
"org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"
id=
"sessionValidationScheduler"
>
<property name=
"sessionValidationInterval"
value=
"1800000"
>
<property name=
"sessionManager"
ref=
"sessionManager"
>
</property></property></bean>
<!-- 会话管理器 -->
<bean
class
=
"org.apache.shiro.web.session.mgt.DefaultWebSessionManager"
id=
"sessionManager"
>
<property name=
"globalSessionTimeout"
value=
"1800000"
>
<property name=
"deleteInvalidSessions"
value=
"true"
>
<property name=
"sessionValidationSchedulerEnabled"
value=
"true"
>
<property name=
"sessionValidationScheduler"
ref=
"sessionValidationScheduler"
>
<property name=
"sessionIdCookieEnabled"
property=
""
ref=
"<span style="
value=
"true"
>
<property name=
"sessionIdCookie"
ref=
"sessionIdCookie"
>
</property></property></property></property></property></property></bean>
<span style=
"color:#ff0000;"
><bean
class
=
"org.calonlan.security.component.CustomShiroSessionDao"
id=
"customShiroSessionDAO"
>
<property name=
"shiroSessionRepository"
ref=
"jedisShiroSessionRepository"
>
//自己定义的sessiondao
</property></bean></span>
<span style=
"color:#ff0000;"
> <bean
class
=
"org.calonlan.security.component.JedisShiroSessionRepository"
id=
"jedisShiroSessionRepository"
>
<property name=
"redisManager"
ref=
"redisManager"
></property>
</bean></span>
<span style=
"color:#ff0000;"
><bean
class
=
"org.calonlan.security.component.RedisManager"
id=
"redisManager"
></bean>
//注册上面实现的redisManager到spring中</span>
<span style=
"background-color: rgb(255, 0, 0);"
><bean
class
=
"org.calonlan.security.component.JedisShiroCacheManager"
id=
"jedisShiroCacheManager"
>
<property name=
"redisManager"
ref=
"redisManager"
></property>
</bean></span><span style=
"background-color: rgb(255, 255, 255);"
>
</span>
<span style=
"color:#ff0000;"
> <bean
class
=
"org.calonlan.security.component.CustomShiroCacheManager"
id=
"customShiroCacheManager"
>
<property name=
"shrioCacheManager"
ref=
"jedisShiroCacheManager"
></property>
</bean></span>
<!-- 安全管理器 -->
<bean
class
=
"org.apache.shiro.web.mgt.DefaultWebSecurityManager"
id=
"securityManager"
>
<property name=
"realm"
ref=
"userRealm"
>
<property name=
"sessionManager"
ref=
"sessionManager"
>
<property name=
"rememberMeManager"
property=
""
ref=
"rememberMeManager"
>
</property></property></property></bean>
<!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean
class
=
"org.springframework.beans.factory.config.MethodInvokingFactoryBean"
>
<property name=
"staticMethod"
value=
"org.apache.shiro.SecurityUtils.setSecurityManager"
>
<property name=
"arguments"
ref=
"securityManager"
>
</property></property></bean>
<!-- 基于Form表单的身份验证过滤器 -->
<bean
class
=
"org.apache.shiro.web.filter.authc.FormAuthenticationFilter"
id=
"formAuthenticationFilter"
>
<property name=
"usernameParam"
value=
"username"
>
<property name=
"passwordParam"
value=
"password"
>
<property name=
"rememberMeParam"
value=
"rememberMe"
>
<property name=
"loginUrl"
value=
"/login"
>
</property></property></property></property></bean>
<bean
class
=
"org.calonlan.security.web.shiro.filter.SysUserFilter"
id=
"sysUserFilter"
>
<!-- Shiro的Web过滤器 -->
<bean
class
=
"org.apache.shiro.spring.web.ShiroFilterFactoryBean"
id=
"shiroFilter"
>
<property name=
"securityManager"
ref=
"securityManager"
>
<!-- 逻辑上正确,不起作用 -->
<property name=
"loginUrl"
value=
"/login"
>
<property name=
"successUrl"
value=
"/admin/index"
>
<property name=
"filters"
>
<util:map>
<entry key=
"authc"
value-ref=
"formAuthenticationFilter"
>
<entry key=
"sysUser"
value-ref=
"sysUserFilter"
>
</entry></entry></util:map>
</property>
<property name=
"filterChainDefinitions"
>
<value>
/img/** =anon
/ueditor/jsp/upload/** =anon
/login = authc
/authenticated = authc
/css/** = anon
/common/** = anon
/js/** = anon
/admin/** = user,sysUser
//*=anon
</value>
</property>
</property></property></property></bean>
<!-- Shiro生命周期处理器 -->
<bean
class
=
"org.apache.shiro.spring.LifecycleBeanPostProcessor"
id=
"lifecycleBeanPostProcessor"
>
</bean></bean></bean></beans>
|
主要看上图的红色部分:其中customShiroSessionDAO、jedisShiroSessionRepository用来处理session;customShiroCacheManager、jedisShiroCacheManager用来处理缓存。
他们的源代码如下:
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
|
package
org.calonlan.security.component;
import
java.io.Serializable;
import
java.util.Collection;
import
org.apache.shiro.session.Session;
import
org.apache.shiro.session.UnknownSessionException;
import
org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
public
class
CustomShiroSessionDao
extends
AbstractSessionDAO {
private
ShiroSessionRepository shiroSessionRepository;
public
ShiroSessionRepository getShiroSessionRepository() {
return
shiroSessionRepository;
}
public
void
setShiroSessionRepository(
ShiroSessionRepository shiroSessionRepository) {
this
.shiroSessionRepository = shiroSessionRepository;
}
@Override
public
void
delete(Session session) {
if
(session ==
null
) {
System.out.println(
"错误"
);
return
;
}
Serializable id = session.getId();
if
(id !=
null
)
getShiroSessionRepository().deleteSession(id);
}
@Override
public
Collection<session> getActiveSessions() {
return
getShiroSessionRepository().getAllSessions();
}
@Override
public
void
update(Session session)
throws
UnknownSessionException {
getShiroSessionRepository().saveSession(session);
}
@Override
protected
Serializable doCreate(Session session) {
Serializable sessionId =
this
.generateSessionId(session);
this
.assignSessionId(session, sessionId);
getShiroSessionRepository().saveSession(session);
return
sessionId;
}
@Override
protected
Session doReadSession(Serializable sessionId) {
return
getShiroSessionRepository().getSession(sessionId);
}
}
</session>
|
这里我们是继承了shiro的AbstractSessionDAO,然后仿照shiro的模式,给他一个shiroSessionRepository,来进行详细的session存储操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package
org.calonlan.security.component;
import
java.io.Serializable;
import
java.util.Collection;
import
org.apache.shiro.session.Session;
public
interface
ShiroSessionRepository {
void
saveSession(Session session);
void
deleteSession(Serializable sessionId);
Session getSession(Serializable sessionId);
Collection<session> getAllSessions();
}</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
|
package
org.calonlan.security.component;
import
java.io.Serializable;
import
java.util.Collection;
import
java.util.HashSet;
import
java.util.Set;
import
org.apache.shiro.session.Session;
public
class
JedisShiroSessionRepository
implements
ShiroSessionRepository {
/**
*
* redis session key 前缀
*
* */
private
final
String REDIS_SHIRO_SESSION =
"shiro-session"
;
private
RedisManager redisManager;
@Override
public
void
saveSession(Session session) {
redisManager.init();
if
(session ==
null
|| session.getId() ==
null
) {
System.out.println(
"session 或者 session ID 为空"
);
}
byte
[] key = SerializeUtils.serialize(getRedisSessionKey(session
.getId()));
byte
[] value = SerializeUtils.serialize(session);
Long timeOut = session.getTimeout() /
1000
;
redisManager.set(key, value, Integer.parseInt(timeOut.toString()));
}
@Override
public
void
deleteSession(Serializable sessionId) {
redisManager.init();
if
(sessionId ==
null
) {
System.out.println(
"id为空"
);
}
redisManager.del(SerializeUtils
.serialize(getRedisSessionKey(sessionId)));
}
@Override
public
Session getSession(Serializable sessionId) {
redisManager.init();
if
(
null
== sessionId) {
System.out.println(
"id为空"
);
return
null
;
}
Session session =
null
;
byte
[] value = redisManager.get(SerializeUtils
.serialize(getRedisSessionKey(sessionId)));
if
(
null
== value)
return
null
;
session = (Session) SerializeUtils.deserialize(value);
return
session;
}
@Override
public
Collection<session> getAllSessions() {
redisManager.init();
Set<session> sessions =
new
HashSet<session>();
Set<
byte
[]> byteKeys = redisManager
.keys(
this
.REDIS_SHIRO_SESSION +
"*"
);
if
(byteKeys !=
null
&& byteKeys.size() >
0
) {
for
(
byte
[] bs : byteKeys) {
Session s = (Session) SerializeUtils.deserialize(redisManager
.get(bs));
sessions.add(s);
}
}
return
sessions;
}
/**
* 获取redis中的session key
*
* @param sessionId
* @return
*/
private
String getRedisSessionKey(Serializable sessionId) {
return
this
.REDIS_SHIRO_SESSION + sessionId;
}
public
RedisManager getRedisManager() {
return
redisManager;
}
public
void
setRedisManager(RedisManager redisManager) {
this
.redisManager = redisManager;
}
public
JedisShiroSessionRepository() {
}
// public static void main(String[] args) {
// Jedis jj = new Jedis("localhost");
// //jj.set("key2", "232323231=========");
// String ss = jj.get("key1");
// System.out.println(jj.get("key2"));
// System.out.println(ss);
// }
}
</
byte
[]></session></session></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
|
package
org.calonlan.security.component;
import
org.apache.shiro.cache.Cache;
import
org.apache.shiro.cache.CacheException;
import
org.apache.shiro.cache.CacheManager;
import
org.apache.shiro.util.Destroyable;
public
class
CustomShiroCacheManager
implements
CacheManager, Destroyable {
private
ShiroCacheManager shrioCacheManager;
public
ShiroCacheManager getShrioCacheManager() {
return
shrioCacheManager;
}
public
void
setShrioCacheManager(ShiroCacheManager shrioCacheManager) {
this
.shrioCacheManager = shrioCacheManager;
}
@Override
public
void
destroy()
throws
Exception {
getShrioCacheManager().destroy();
}
@Override
public
<k, v=
""
> Cache<k, v=
""
> getCache(String name)
throws
CacheException {
return
getShrioCacheManager().getCache(name);
}
}
</k,></k,>
|
1
2
3
4
5
6
7
8
9
10
|
package
org.calonlan.security.component;
import
org.apache.shiro.cache.Cache;
public
interface
ShiroCacheManager {
<k, v=
""
> Cache<k, v=
""
> getCache(String name);
void
destroy();
}
</k,></k,>
|
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
|
package
org.calonlan.security.component;
import
org.apache.shiro.cache.Cache;
public
class
JedisShiroCacheManager
implements
ShiroCacheManager {
private
RedisManager redisManager;
public
RedisManager getRedisManager() {
return
redisManager;
}
public
void
setRedisManager(RedisManager redisManager) {
this
.redisManager = redisManager;
}
@Override
public
<k, v=
""
> Cache<k, v=
""
> getCache(String name) {
return
new
JedisShiroCache<k, v=
""
>(redisManager, name);
}
@Override
public
void
destroy() {
redisManager.init();
redisManager.flushDB();
}
}
</k,></k,></k,>
|
具体的使用就如如上代码所示,为什么要弄一个什么ShiroCacheManager和ShiroSessionRepository接口呢,我想各位大侠也能知道的。有了这个两个接口,我们就可以通过这个两个接口来实现更多形式的shiro的session和缓存的管理了。
在很多地方使用到了SerializeUtils,它的作用就是把对象转化为byte数组,或把byte数组转化为对象。源代码如下:
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
|
package
org.calonlan.security.component;
import
java.io.ByteArrayInputStream;
import
java.io.ByteArrayOutputStream;
import
java.io.IOException;
import
java.io.ObjectInputStream;
import
java.io.ObjectOutputStream;
public
class
SerializeUtils {
public
static
byte
[] serialize(Object o) {
ByteArrayOutputStream out =
new
ByteArrayOutputStream();
try
{
ObjectOutputStream outo =
new
ObjectOutputStream(out);
outo.writeObject(o);
}
catch
(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return
out.toByteArray();
}
public
static
Object deserialize(
byte
[] b) {
ObjectInputStream oin;
try
{
oin =
new
ObjectInputStream(
new
ByteArrayInputStream(b));
try
{
return
oin.readObject();
}
catch
(ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return
null
;
}
}
catch
(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return
null
;
}
}
}
|
然后项目的运行结果如下:
从图中可以看到,我登录后,session信息已经保存到了redis数据库中。多个tomcat做负载均衡的测试结果也很良好,但是我这个笔记本没有安装那种环境,所以无法测试。这都是个人一点小东西,各位大神勿喷。