diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java index c3657d1d..034bd7d4 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java @@ -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 userDtoCache = new ConcurrentHashMap<>(); + + final static Map> 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 dataScopes = jwtUserDto.getDataScopes(); - dataScopes.clear(); - dataScopes.addAll(dataService.getDeptIds(jwtUserDto.getUser())); - searchDb = false; - } - if (searchDb) { + Future 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 call=()->getJwtBySearchDB(username); + FutureTask 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 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()); } } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/domain/User.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/domain/User.java index 6ee29e84..b4d11bda 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/system/domain/User.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/domain/User.java @@ -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 roles; - @ManyToMany + @ManyToMany(fetch = FetchType.EAGER) @ApiModelProperty(value = "用户岗位") @JoinTable(name = "sys_users_jobs", joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, diff --git a/eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java b/eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java index 4d7f55c8..ef608495 100644 --- a/eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java +++ b/eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java @@ -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) + "毫秒"); } + }