<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                在小程序登陸的時候,在`MiniAppAuthenticationProvider`中我們看到這樣一行代碼 ```java yamiUserDetailsService.insertUserIfNecessary(appConnect); ``` 這便是商城用戶創建的代碼,在`YamiUserServiceImpl#insertUserIfNecessary()`方法中,有一個這樣的注解 ```java @RedisLock(lockName = "insertUser", key = "#appConnect.appId + ':' + #appConnect.bizUserId") ``` 這里便用了分布式鎖,為什么我們要在這里使用鎖?分布式鎖又是什么? - 由于用戶是通過登錄直接注冊的,如果一個用戶在不刻意之間,又或者前端寫的東西有點問題,這就會導致整個系統創建了兩個相同的用戶,這是非常危險的事情,所以創建用戶這里必須加鎖。 - 至于為什么使用分布式鎖,是因為我們雖然沒有用上spring cloud、dubbo之類的東西,實際上我們也是希望我們的商城可以多實例部署的,也就是可以搞分布式的。因此用了分布式鎖 分布式鎖,簡單來說就是鎖,而且還是適合分布式環境的。分布式說起來也很奇怪,要是有什么不能共享的東西,那就抽出來共享。比如本地數據緩存不能共享,那么就抽出一個如redis之類的東西,進行共享。session不能共享,那么就將session抽出來,丟到redis之類的東西,又能共享了。 鎖不能共享,同樣可以丟一個標記到redis,由于redis是單線程的,所以也不用擔心redis的線程安全的問題。這個標記就是一個鎖的標記,那樣你就實現了分布式鎖... 我們看回`@RedisLock` 該類,里面有個`expire()`方法 ```java /** * 過期毫秒數,默認為5000毫秒 * * @return 鎖的時間 */ int expire() default 5000; ``` 由于網絡穩定、宕機等各種原因,分布式鎖,必須要有過期時間,否則鎖無法釋放的話,會阻塞一片的實例。 ## 實現一個簡單的分布式鎖注解 由于自己去實現redis的分布式鎖,是比較困難的問題,還要考慮redis復制,宕機之類的問題,所以我們使用一個比較優秀的開源項目 **redisson**來實現我們的分布式鎖 被`@RedisLock`所注解的方法,會被 `RedisLockAspect` 進行切面管理,代碼如下: ```java @Around("@annotation(redisLock)") public Object around(ProceedingJoinPoint joinPoint, RedisLock redisLock) throws Throwable { String spel = redisLock.key(); String lockName = redisLock.lockName(); // redissonClient 也就是通過redisson 進行對鎖管理 RLock rLock = redissonClient.getLock(getRedisKey(joinPoint,lockName,spel)); rLock.lock(redisLock.expire(),redisLock.timeUnit()); Object result = null; try { //執行方法 result = joinPoint.proceed(); } finally { rLock.unlock(); } return result; } ``` ## 識別spel表達式 在`@RedisLock(lockName = "insertUser", key = "#appConnect.appId + ':' + #appConnect.bizUserId")`中 `#appConnect.appId` 也僅僅是表示一串字符串而已,而能將其變成表達式,需要一定的轉換`SpelUtil.parse` ```java /** * 支持 #p0 參數索引的表達式解析 * @param rootObject 根對象,method 所在的對象 * @param spel 表達式 * @param method ,目標方法 * @param args 方法入參 * @return 解析后的字符串 */ public static String parse(Object rootObject,String spel, Method method, Object[] args) { if (StrUtil.isBlank(spel)) { return StrUtil.EMPTY; } //獲取被攔截方法參數名列表(使用Spring支持類庫) LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); String[] paraNameArr = u.getParameterNames(method); if (ArrayUtil.isEmpty(paraNameArr)) { return spel; } //使用SPEL進行key的解析 ExpressionParser parser = new SpelExpressionParser(); //SPEL上下文 StandardEvaluationContext context = new MethodBasedEvaluationContext(rootObject,method,args,u); //把方法參數放入SPEL上下文中 for (int i = 0; i < paraNameArr.length; i++) { context.setVariable(paraNameArr[i], args[i]); } return parser.parseExpression(spel).getValue(context, String.class); } ``` 同時我們也害怕redis的key發生沖突,所以會對key加上一些統一的前綴: redis 鎖的key能夠識別`spel` 表達式,并且不和其他方法的鎖名稱或緩存名稱重復 ```java /** * 將spel表達式轉換為字符串 * @param joinPoint 切點 * @return redisKey */ private String getRedisKey(ProceedingJoinPoint joinPoint,String lockName,String spel) { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method targetMethod = methodSignature.getMethod(); Object target = joinPoint.getTarget(); Object[] arguments = joinPoint.getArgs(); return REDISSON_LOCK_PREFIX + lockName + StrUtil.COLON + SpelUtil.parse(target,spel, targetMethod, arguments); } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看