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
931ecb3b
Unverified
Commit
931ecb3b
authored
Nov 23, 2021
by
dante
Committed by
GitHub
Nov 23, 2021
Browse files
Fix cache by future (#652)
* 利用future回调避免并发调用时有多个线程同时去数据库查询,导致消耗额外资源。经过测试在8个线程并发查询时性能提升 * 修复缓存测试时懒加载报错问题 * 调整格式
parent
7b91c440
Changes
3
Hide whitespace changes
Inline
Side-by-side
eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java
View file @
931ecb3b
...
...
@@ -30,7 +30,8 @@ import org.springframework.stereotype.Service;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.*
;
import
java.util.concurrent.atomic.AtomicInteger
;
/**
* @author Zheng Jie
...
...
@@ -53,21 +54,15 @@ public class UserDetailsServiceImpl implements UserDetailsService {
*
* @see {@link UserCacheClean}
*/
static
Map
<
String
,
JwtUserDto
>
userDtoCache
=
new
ConcurrentHashMap
<>();
final
static
Map
<
String
,
Future
<
JwtUserDto
>>
userDtoCache
=
new
ConcurrentHashMap
<>();
public
static
ExecutorService
executor
=
newThreadPool
();
@Override
public
JwtUserDto
loadUserByUsername
(
String
username
)
{
boolean
searchDb
=
true
;
JwtUserDto
jwtUserDto
=
null
;
if
(
loginProperties
.
isCacheEnable
()
&&
userDtoCache
.
containsKey
(
username
))
{
jwtUserDto
=
userDtoCache
.
get
(
username
);
// 检查dataScope是否修改
List
<
Long
>
dataScopes
=
jwtUserDto
.
getDataScopes
();
dataScopes
.
clear
();
dataScopes
.
addAll
(
dataService
.
getDeptIds
(
jwtUserDto
.
getUser
()));
searchDb
=
false
;
}
if
(
searchDb
)
{
Future
<
JwtUserDto
>
future
=
userDtoCache
.
get
(
username
);
if
(!
loginProperties
.
isCacheEnable
())
{
UserDto
user
;
try
{
user
=
userService
.
findByName
(
username
);
...
...
@@ -86,9 +81,86 @@ public class UserDetailsServiceImpl implements UserDetailsService {
dataService
.
getDeptIds
(
user
),
roleService
.
mapToGrantedAuthorities
(
user
)
);
userDtoCache
.
put
(
username
,
jwtUserDto
);
}
return
jwtUserDto
;
}
if
(
future
==
null
)
{
Callable
<
JwtUserDto
>
call
=()->
getJwtBySearchDB
(
username
);
FutureTask
<
JwtUserDto
>
ft
=
new
FutureTask
<>(
call
);
future
=
userDtoCache
.
putIfAbsent
(
username
,
ft
);
if
(
future
==
null
){
future
=
ft
;
executor
.
submit
(
ft
);
}
try
{
return
future
.
get
();
}
catch
(
CancellationException
e
){
userDtoCache
.
remove
(
username
);
}
catch
(
InterruptedException
|
ExecutionException
e
)
{
throw
new
RuntimeException
(
e
.
getMessage
());
}
}
else
{
try
{
jwtUserDto
=
future
.
get
();
}
catch
(
InterruptedException
|
ExecutionException
e
)
{
throw
new
RuntimeException
(
e
.
getMessage
());
}
// 检查dataScope是否修改
List
<
Long
>
dataScopes
=
jwtUserDto
.
getDataScopes
();
dataScopes
.
clear
();
dataScopes
.
addAll
(
dataService
.
getDeptIds
(
jwtUserDto
.
getUser
()));
}
return
jwtUserDto
;
}
private
JwtUserDto
getJwtBySearchDB
(
String
username
)
{
UserDto
user
;
try
{
user
=
userService
.
findByName
(
username
);
}
catch
(
EntityNotFoundException
e
)
{
// SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException
throw
new
UsernameNotFoundException
(
""
,
e
);
}
if
(
user
==
null
)
{
throw
new
UsernameNotFoundException
(
""
);
}
else
{
if
(!
user
.
getEnabled
())
{
throw
new
BadRequestException
(
"账号未激活!"
);
}
JwtUserDto
jwtUserDto
=
new
JwtUserDto
(
user
,
dataService
.
getDeptIds
(
user
),
roleService
.
mapToGrantedAuthorities
(
user
)
);
return
jwtUserDto
;
}
}
public
static
ExecutorService
newThreadPool
()
{
ThreadFactory
namedThreadFactory
=
new
ThreadFactory
()
{
final
AtomicInteger
sequence
=
new
AtomicInteger
(
1
);
@Override
public
Thread
newThread
(
Runnable
r
)
{
Thread
thread
=
new
Thread
(
r
);
int
seq
=
this
.
sequence
.
getAndIncrement
();
thread
.
setName
(
"future-task-thread"
+
(
seq
>
1
?
"-"
+
seq
:
""
));
if
(!
thread
.
isDaemon
())
{
thread
.
setDaemon
(
true
);
}
return
thread
;
}
};
return
new
ThreadPoolExecutor
(
10
,
200
,
0L
,
TimeUnit
.
MILLISECONDS
,
new
LinkedBlockingQueue
<>(
1024
),
namedThreadFactory
,
new
ThreadPoolExecutor
.
AbortPolicy
());
}
}
eladmin-system/src/main/java/me/zhengjie/modules/system/domain/User.java
View file @
931ecb3b
...
...
@@ -45,14 +45,14 @@ public class User extends BaseEntity implements Serializable {
@ApiModelProperty
(
value
=
"ID"
,
hidden
=
true
)
private
Long
id
;
@ManyToMany
@ManyToMany
(
fetch
=
FetchType
.
EAGER
)
@ApiModelProperty
(
value
=
"用户角色"
)
@JoinTable
(
name
=
"sys_users_roles"
,
joinColumns
=
{
@JoinColumn
(
name
=
"user_id"
,
referencedColumnName
=
"user_id"
)},
inverseJoinColumns
=
{
@JoinColumn
(
name
=
"role_id"
,
referencedColumnName
=
"role_id"
)})
private
Set
<
Role
>
roles
;
@ManyToMany
@ManyToMany
(
fetch
=
FetchType
.
EAGER
)
@ApiModelProperty
(
value
=
"用户岗位"
)
@JoinTable
(
name
=
"sys_users_jobs"
,
joinColumns
=
{
@JoinColumn
(
name
=
"user_id"
,
referencedColumnName
=
"user_id"
)},
...
...
eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java
View file @
931ecb3b
...
...
@@ -5,7 +5,11 @@ import org.junit.Test;
import
org.junit.runner.RunWith
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
javax.annotation.Resource
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
@RunWith
(
SpringRunner
.
class
)
@SpringBootTest
(
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
RANDOM_PORT
)
...
...
@@ -13,14 +17,19 @@ public class LoginCacheTest {
@Resource
(
name
=
"userDetailsService"
)
private
UserDetailsServiceImpl
userDetailsService
;
ExecutorService
executor
=
Executors
.
newCachedThreadPool
();
@Test
public
void
testCache
()
{
public
void
testCache
()
throws
InterruptedException
{
long
start1
=
System
.
currentTimeMillis
();
int
size
=
10000
;
int
size
=
1000
;
CountDownLatch
latch
=
new
CountDownLatch
(
size
);
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
userDetailsService
.
loadUserByUsername
(
"admin"
);
executor
.
submit
(()
->
userDetailsService
.
loadUserByUsername
(
"admin"
));
latch
.
countDown
();
}
latch
.
await
();
long
end1
=
System
.
currentTimeMillis
();
//关闭缓存
userDetailsService
.
setEnableCache
(
false
);
...
...
@@ -31,4 +40,5 @@ public class LoginCacheTest {
long
end2
=
System
.
currentTimeMillis
();
System
.
out
.
print
(
"使用缓存:"
+
(
end1
-
start1
)
+
"毫秒\n 不使用缓存:"
+
(
end2
-
start2
)
+
"毫秒"
);
}
}
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