昨天在集成shiro-redis的時候,使用sessionId在其他微服務獲取用戶的session時,發生錯誤:There is no session with id [xxx]。
查遍了所有資料,基本上說的時cookieId造成的,和我的問題明顯不一致,無奈只能down源碼,調試跟蹤。發現錯誤代碼是因為RedisSessionDAO.doReadSession方法catch了異常后,沒有拋出造成的,直接返回一個session 為null的返回值,上代碼:
@Override protected Session doReadSession(Serializable sessionId) { if (sessionId == null) { logger.warn("session id is null"); return null; } if (this.sessionInMemoryEnabled) { Session session = getSessionFromThreadLocal(sessionId); if (session != null) { return session; } } Session session = null; logger.debug("read session from redis"); try { session = (Session) valueSerializer.deserialize(redisManager.get(keySerializer.serialize(getRedisSessionKey(sessionId)))); if (this.sessionInMemoryEnabled) { setSessionToThreadLocal(sessionId, session); } } catch (SerializationException e) { logger.error("read session error. settionId=" + sessionId); } return session; }
這句代碼:session = (Session) valueSerializer.deserialize(redisManager.get(keySerializer.serialize(getRedisSessionKey(sessionId))));是我的使用方法中出現There is no session with id的原因。因為我封裝 的AuthUser,在另外的微服務中未引用,造成了反序列化異常。
而RedisSeesionDAO在此處catch后,並沒有再繼續拋出,從而使AbstractSessionDAO.readSeesion方法調用RedisSessionDAO重寫的doReadSession后,得到了為null的session,認為沒有獲取到session,然后拋出There is no session with id錯誤。
readSeesion的代碼:
public Session readSession(Serializable sessionId) throws UnknownSessionException { Session s = doReadSession(sessionId); if (s == null) { throw new UnknownSessionException("There is no session with id [" + sessionId + "]"); } return s; }
所以,綜合來說,我這次排查那么久,罪魁禍首是RedisSeesionDAO錯誤處理了異常,使上層調用方法不知道內部發生了什么錯誤,使上層方法拋出了一個與實際錯誤不相干的異常,讓我繞了好大的圈子。
公共組件catch異常需謹慎呀-- 不然發生一次次的慘案。