Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Eladmin
Commits
6941b984
Commit
6941b984
authored
Jan 27, 2022
by
TikiWong
Browse files
[代码优化] 添加支持配置的可回收用户缓存
parent
c75b52e1
Changes
5
Hide whitespace changes
Inline
Side-by-side
eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserCacheClean.java
View file @
6941b984
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
package
me.zhengjie.modules.security.service
;
package
me.zhengjie.modules.security.service
;
import
lombok.AllArgsConstructor
;
import
me.zhengjie.utils.StringUtils
;
import
me.zhengjie.utils.StringUtils
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
...
@@ -25,8 +26,11 @@ import org.springframework.stereotype.Component;
...
@@ -25,8 +26,11 @@ import org.springframework.stereotype.Component;
* @apiNote: 用于清理 用户登录信息缓存,为防止Spring循环依赖与安全考虑 ,单独构成工具类
* @apiNote: 用于清理 用户登录信息缓存,为防止Spring循环依赖与安全考虑 ,单独构成工具类
*/
*/
@Component
@Component
@AllArgsConstructor
public
class
UserCacheClean
{
public
class
UserCacheClean
{
private
final
UserCacheManager
userCacheManager
;
/**
/**
* 清理特定用户缓存信息<br>
* 清理特定用户缓存信息<br>
* 用户信息变更时
* 用户信息变更时
...
@@ -35,7 +39,7 @@ public class UserCacheClean {
...
@@ -35,7 +39,7 @@ public class UserCacheClean {
*/
*/
public
void
cleanUserCache
(
String
userName
)
{
public
void
cleanUserCache
(
String
userName
)
{
if
(
StringUtils
.
isNotEmpty
(
userName
))
{
if
(
StringUtils
.
isNotEmpty
(
userName
))
{
U
ser
DetailsServiceImpl
.
USER_DTO_CACHE
.
remove
(
userName
);
u
ser
CacheManager
.
remove
(
userName
);
}
}
}
}
...
@@ -44,6 +48,6 @@ public class UserCacheClean {
...
@@ -44,6 +48,6 @@ public class UserCacheClean {
* ,如发生角色授权信息变化,可以简便的全部失效缓存
* ,如发生角色授权信息变化,可以简便的全部失效缓存
*/
*/
public
void
cleanAll
()
{
public
void
cleanAll
()
{
U
ser
DetailsServiceImpl
.
USER_DTO_CACHE
.
clear
();
u
ser
CacheManager
.
clear
();
}
}
}
}
eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserCacheManager.java
0 → 100644
View file @
6941b984
package
me.zhengjie.modules.security.service
;
import
lombok.extern.slf4j.Slf4j
;
import
me.zhengjie.modules.security.service.dto.JwtUserDto
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.stereotype.Component
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.Future
;
import
java.util.concurrent.atomic.AtomicBoolean
;
/**
* 用户缓存
*
* @author TikiWong
* @date 2022/1/27 8:23
**/
@Slf4j
@Component
public
class
UserCacheManager
{
@Value
(
"${user-cache.min-evictable-size}"
)
private
int
minEvictableSize
;
@Value
(
"${user-cache.min-evictable-interval}"
)
private
long
minEvictableInterval
;
@Value
(
"${user-cache.min-idle-time}"
)
private
long
minIdleTime
;
private
final
Map
<
String
,
Node
>
cache
=
new
ConcurrentHashMap
<>();
private
final
AtomicBoolean
expelLock
=
new
AtomicBoolean
(
true
);
private
long
nextMinEvictableTime
=
0
;
public
Future
<
JwtUserDto
>
putIfAbsent
(
String
username
,
Future
<
JwtUserDto
>
ft
)
{
Node
tryNode
=
new
Node
(
ft
);
Node
node
=
cache
.
putIfAbsent
(
username
,
tryNode
);
expel
();
return
nodeToDate
(
node
);
}
/**
* 缓存回收
* 为避免超过边界后回收热点数据设置了最小生存时间
* 回收时会保留在最小生存时间内的数据
**/
public
void
expel
()
{
long
now
=
System
.
currentTimeMillis
();
if
(
cache
.
size
()
<
minEvictableSize
||
now
<
nextMinEvictableTime
&&
!
expelLock
.
compareAndSet
(
true
,
false
))
{
return
;
}
long
oldestTime
=
now
;
int
evictedCount
=
0
;
try
{
Iterator
<
Map
.
Entry
<
String
,
Node
>>
iterator
=
cache
.
entrySet
().
iterator
();
while
(
iterator
.
hasNext
())
{
Map
.
Entry
<
String
,
Node
>
entry
=
iterator
.
next
();
long
nodeTime
=
entry
.
getValue
().
getTime
();
if
(
nodeTime
+
minIdleTime
<
now
)
{
iterator
.
remove
();
evictedCount
++;
}
oldestTime
=
Math
.
min
(
oldestTime
,
nodeTime
);
}
}
finally
{
this
.
nextMinEvictableTime
=
Math
.
max
(
now
+
minEvictableInterval
,
oldestTime
);
expelLock
.
set
(
true
);
log
.
info
(
"回收掉【{}】条用户缓存, 剩余缓存数为【{}】,下次可回收时间为【{}】秒后"
,
evictedCount
,
cache
.
size
(),
(
this
.
nextMinEvictableTime
-
now
)
/
1000
);
}
}
public
Future
<
JwtUserDto
>
get
(
String
username
)
{
return
nodeToDate
(
cache
.
get
(
username
));
}
public
void
clear
()
{
cache
.
clear
();
}
public
void
remove
(
String
username
)
{
cache
.
remove
(
username
);
}
private
Future
<
JwtUserDto
>
nodeToDate
(
Node
node
)
{
return
node
==
null
?
null
:
node
.
getData
();
}
private
static
class
Node
{
private
final
Future
<
JwtUserDto
>
data
;
private
final
long
time
;
public
Node
(
Future
<
JwtUserDto
>
data
)
{
this
.
data
=
data
;
this
.
time
=
System
.
currentTimeMillis
();
}
public
Future
<
JwtUserDto
>
getData
()
{
return
data
;
}
public
long
getTime
()
{
return
time
;
}
}
}
eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java
View file @
6941b984
...
@@ -29,7 +29,6 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
...
@@ -29,7 +29,6 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.*
;
import
java.util.concurrent.*
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.atomic.AtomicInteger
;
...
@@ -45,17 +44,12 @@ public class UserDetailsServiceImpl implements UserDetailsService {
...
@@ -45,17 +44,12 @@ public class UserDetailsServiceImpl implements UserDetailsService {
private
final
DataService
dataService
;
private
final
DataService
dataService
;
private
final
LoginProperties
loginProperties
;
private
final
LoginProperties
loginProperties
;
private
final
UserCacheManager
USER_DTO_CACHE
;
public
void
setEnableCache
(
boolean
enableCache
)
{
public
void
setEnableCache
(
boolean
enableCache
)
{
this
.
loginProperties
.
setCacheEnable
(
enableCache
);
this
.
loginProperties
.
setCacheEnable
(
enableCache
);
}
}
/**
* 用户信息缓存
*
* @see {@link UserCacheClean}
*/
final
static
Map
<
String
,
Future
<
JwtUserDto
>>
USER_DTO_CACHE
=
new
ConcurrentHashMap
<>();
public
static
ExecutorService
executor
=
newThreadPool
();
public
static
ExecutorService
executor
=
newThreadPool
();
@Override
@Override
...
@@ -68,7 +62,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
...
@@ -68,7 +62,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
user
=
userService
.
findByName
(
username
);
user
=
userService
.
findByName
(
username
);
}
catch
(
EntityNotFoundException
e
)
{
}
catch
(
EntityNotFoundException
e
)
{
// SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException
// SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException
throw
new
UsernameNotFoundException
(
""
,
e
);
throw
new
UsernameNotFoundException
(
username
,
e
);
}
}
if
(
user
==
null
)
{
if
(
user
==
null
)
{
throw
new
UsernameNotFoundException
(
""
);
throw
new
UsernameNotFoundException
(
""
);
...
@@ -85,25 +79,26 @@ public class UserDetailsServiceImpl implements UserDetailsService {
...
@@ -85,25 +79,26 @@ public class UserDetailsServiceImpl implements UserDetailsService {
return
jwtUserDto
;
return
jwtUserDto
;
}
}
if
(
future
==
null
)
{
if
(
future
==
null
)
{
Callable
<
JwtUserDto
>
call
=
()->
getJwtBySearchDb
(
username
);
Callable
<
JwtUserDto
>
call
=
()
->
getJwtBySearchDb
(
username
);
FutureTask
<
JwtUserDto
>
ft
=
new
FutureTask
<>(
call
);
FutureTask
<
JwtUserDto
>
ft
=
new
FutureTask
<>(
call
);
future
=
USER_DTO_CACHE
.
putIfAbsent
(
username
,
ft
);
future
=
USER_DTO_CACHE
.
putIfAbsent
(
username
,
ft
);
if
(
future
==
null
){
if
(
future
==
null
)
{
future
=
ft
;
future
=
ft
;
executor
.
submit
(
ft
);
executor
.
submit
(
ft
);
}
}
try
{
try
{
return
future
.
get
();
return
future
.
get
();
}
catch
(
CancellationException
e
){
}
catch
(
CancellationException
e
)
{
USER_DTO_CACHE
.
remove
(
username
);
USER_DTO_CACHE
.
remove
(
username
);
}
catch
(
InterruptedException
|
ExecutionException
e
)
{
System
.
out
.
println
(
"error"
+
Thread
.
currentThread
().
getName
());
}
catch
(
InterruptedException
|
ExecutionException
e
)
{
throw
new
RuntimeException
(
e
.
getMessage
());
throw
new
RuntimeException
(
e
.
getMessage
());
}
}
}
else
{
}
else
{
try
{
try
{
jwtUserDto
=
future
.
get
();
jwtUserDto
=
future
.
get
();
}
catch
(
InterruptedException
|
ExecutionException
e
)
{
}
catch
(
InterruptedException
|
ExecutionException
e
)
{
throw
new
RuntimeException
(
e
.
getMessage
());
throw
new
RuntimeException
(
e
.
getMessage
());
}
}
// 检查dataScope是否修改
// 检查dataScope是否修改
...
...
eladmin-system/src/main/resources/config/application.yml
View file @
6941b984
...
@@ -54,3 +54,12 @@ code:
...
@@ -54,3 +54,12 @@ code:
#密码加密传输,前端公钥加密,后端私钥解密
#密码加密传输,前端公钥加密,后端私钥解密
rsa
:
rsa
:
private_key
:
MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
private_key
:
MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==
# 内存用户缓存配置
user-cache
:
# 最小回收数(当缓存数量达到此值时进行回收)
min-evictable-size
:
512
# 最小回收间隔
min-evictable-interval
:
1800000
# 最小存活时间 (ms)
min-idle-time
:
3600000
\ No newline at end of file
eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java
View file @
6941b984
...
@@ -41,4 +41,24 @@ public class LoginCacheTest {
...
@@ -41,4 +41,24 @@ public class LoginCacheTest {
System
.
out
.
print
(
"使用缓存:"
+
(
end1
-
start1
)
+
"毫秒\n 不使用缓存:"
+
(
end2
-
start2
)
+
"毫秒"
);
System
.
out
.
print
(
"使用缓存:"
+
(
end1
-
start1
)
+
"毫秒\n 不使用缓存:"
+
(
end2
-
start2
)
+
"毫秒"
);
}
}
@Test
public
void
testCacheManager
()
throws
InterruptedException
{
int
size
=
1000
;
CountDownLatch
latch
=
new
CountDownLatch
(
size
);
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
int
mod
=
i
%
10
;
executor
.
submit
(()
->
{
try
{
Thread
.
sleep
(
mod
*
2
+
(
int
)
(
Math
.
random
()
*
10000
));
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
}
userDetailsService
.
loadUserByUsername
(
"admin"
+
mod
);
latch
.
countDown
();
System
.
out
.
println
(
"剩余未完成数量"
+
latch
.
getCount
());
});
}
latch
.
await
();
}
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment