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..c85dd658 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,42 +54,109 @@ 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); + Future future=userDtoCache.get(username); + if(!loginProperties.isCacheEnable()){ + 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 = new JwtUserDto( + user, + dataService.getDeptIds(user), + roleService.mapToGrantedAuthorities(user) + ); + } + return jwtUserDto; + } + + if (future!=null) { + 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())); - searchDb = false; - } - if (searchDb) { - UserDto user; - try { - user = userService.findByName(username); - } catch (EntityNotFoundException e) { - // SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException - throw new UsernameNotFoundException("", e); + }else{ + Callable call=()->getJwtBySearchDB(username); + FutureTask ft=new FutureTask<>(call); + future=userDtoCache.putIfAbsent(username,ft); + if(future==null){ + future=ft; + executor.submit(ft); } - if (user == null) { - throw new UsernameNotFoundException(""); - } else { - if (!user.getEnabled()) { - throw new BadRequestException("账号未激活!"); - } - jwtUserDto = new JwtUserDto( - user, - dataService.getDeptIds(user), - roleService.mapToGrantedAuthorities(user) - ); - userDtoCache.put(username, jwtUserDto); + try{ + return future.get(); + }catch(CancellationException e){ + userDtoCache.remove(username); + }catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e.getMessage()); } } 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(8, 200, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(1024), + namedThreadFactory, + new ThreadPoolExecutor.AbortPolicy()); + } } 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) + "毫秒"); } + }