Shiro AbstractNativeSessionManager的设计概念
AbstractNativeSessionManager具体实现了SessionManager的行为和NativeSessionManager的行为
具备了Session监听器,session创建时监听器起作用
具体实现SessionManager的行为之 Session start(SessionContext context);
public Session start(SessionContext context) { // 抽象创建Session的行为,后文详解#1 Session session = createSession(context); // 为Session设置过期时间,后文详解#2 applyGlobalSessionTimeout(session); // 开启Session中的行为,后文详解#3 onStart(session, context); // 通知监听器执行Session创建中行为,后文详解#4 notifyStart(session); // 包装Session,最终要实现的Session可以存储在除了内存外的其他介质中(如Redis),后文详解#5 return createExposedSession(session, context); }
书接前文#1
创建session的过程也会经过几道工序,所以需要抽象,让其子类在创建Session的过程中执行自身特有的行为
protected abstract Session createSession(SessionContext context) throws AuthorizationException;
AbstractValidatingSessionManager执行创建Session的行为
protected Session createSession(SessionContext context) throws AuthorizationException {
// 如果有必要的话对Session进行有效性校验 enableSessionValidationIfNecessary();
// 具体创建Session的行为,继续抽象化 return doCreateSession(context); }
protected abstract Session doCreateSession(SessionContext initData) throws AuthorizationException;
DefaultSessionManager具体执行创建Session的工作,因为其有SessionFactory和SessionDao其具体职能就是创建Session
protected Session doCreateSession(SessionContext context) { Session s = newSessionInstance(context); if (log.isTraceEnabled()) { log.trace("Creating session for host {}", s.getHost()); } create(s); return s; }
// SessionFactory负责创建基础Session protected Session newSessionInstance(SessionContext context) { return getSessionFactory().createSession(context); } // SessionDao负责存储Session到介质中 protected void create(Session session) { if (log.isDebugEnabled()) { log.debug("Creating new EIS record for new session instance [" + session + "]"); } sessionDAO.create(session); }
书接前文#2
protected void applyGlobalSessionTimeout(Session session) { // 从AbstractSessionManager中获得全局Session过期时间,然后为Session设置上 session.setTimeout(getGlobalSessionTimeout()); // 执行Session更新时的行为,默认什么都不执行,子类可覆盖执行其特有的行为 onChange(session); } protected void onChange(Session s) { }
DefaultSessionManager具体执行Session更新时的行为,SessionDao负责更新介质中的Session
protected void onChange(Session session) { sessionDAO.update(session); }
书接前文#3
在开启Session的过程中执行一些行为
protected void onStart(Session session, SessionContext context) { }
DefaultWebSessionManager在开启Session中创建了Cookie,并在Session中存储了一些内容
protected void onStart(Session session, SessionContext context) { super.onStart(session, context); if (!WebUtils.isHttp(context)) { log.debug("SessionContext argument is not HTTP compatible or does not have an HTTP request/response " + "pair. No session ID cookie will be set."); return; } HttpServletRequest request = WebUtils.getHttpRequest(context); HttpServletResponse response = WebUtils.getHttpResponse(context); if (isSessionIdCookieEnabled()) { Serializable sessionId = session.getId(); storeSessionId(sessionId, request, response); } else { log.debug("Session ID cookie is disabled. No cookie has been set for new session with id {}", session.getId()); } request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE); }
书接前文#4
protected void notifyStart(Session session) { for (SessionListener listener : this.listeners) { listener.onStart(session); } }
书接前文#5
protected Session createExposedSession(Session session, SessionContext context) { return new DelegatingSession(this, new DefaultSessionKey(session.getId())); }
DelegatingSession中具备了NativeSessionManager(SessionManager管理器创建的Session中又包含了SessionManager管理器),Session获得过期时间的过程是这样的:Session.getTimeout() ==> sessionManager.getTimeout(sessionKey) ==> 去Redis或者什么地方获得Session ==> redisSession.getTimeout()
public DelegatingSession(NativeSessionManager sessionManager, SessionKey key) { if (sessionManager == null) { throw new IllegalArgumentException("sessionManager argument cannot be null."); } if (key == null) { throw new IllegalArgumentException("sessionKey argument cannot be null."); } if (key.getSessionId() == null) { String msg = "The " + DelegatingSession.class.getName() + " implementation requires that the " + "SessionKey argument returns a non-null sessionId to support the " + "Session.getId() invocations."; throw new IllegalArgumentException(msg); } this.sessionManager = sessionManager; this.key = key; }
具体实现SessionManager的行为之 Session getSession(SessionKey key);
public Session getSession(SessionKey key) throws SessionException { // 根据Session的key查找Session(如在Redis介质中查找) Session session = lookupSession(key); // 如果Session存在就包装Session,最终要实现的Session可以存储在除了内存外的其他介质中(如Redis) return session != null ? createExposedSession(session, key) : null; } private Session lookupSession(SessionKey key) throws SessionException { if (key == null) { throw new NullPointerException("SessionKey argument cannot be null."); } return doGetSession(key); } // AbstractNativeSessionManager本身没有查询Session的职能,只能抽象化 protected abstract Session doGetSession(SessionKey key) throws InvalidSessionException;
AbstractValidatingSessionManager又来插一脚发挥其特性,校验Session,其本身也没有查询Session的职能,只能抽象化
protected final Session doGetSession(final SessionKey key) throws InvalidSessionException { // 如果有必要的话对Session进行有效性校验 enableSessionValidationIfNecessary(); log.trace("Attempting to retrieve session with key {}", key); // 根据Session的key检索Session Session s = retrieveSession(key); if (s != null) { // 校验Session validate(s, key); } return s; } // AbstractValidatingSessionManager本身没有查询Session的职能,只能抽象化 protected abstract Session retrieveSession(SessionKey key) throws UnknownSessionException;
DefaultSessionManager有SessionDao,查询Session这个事只能是他来做
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException { // 获得Session的主键(如Redis的key) Serializable sessionId = getSessionId(sessionKey); if (sessionId == null) { log.debug("Unable to resolve session ID from SessionKey [{}]. Returning null to indicate a " + "session could not be found.", sessionKey); return null; } // 从数据源中检索Session Session s = retrieveSessionFromDataSource(sessionId); if (s == null) { //session ID was provided, meaning one is expected to be found, but we couldn't find one: String msg = "Could not find session with ID [" + sessionId + "]"; throw new UnknownSessionException(msg); } return s; } protected Serializable getSessionId(SessionKey sessionKey) { return sessionKey.getSessionId(); } protected Session retrieveSessionFromDataSource(Serializable sessionId) throws UnknownSessionException { return sessionDAO.readSession(sessionId); }
具体实现NativeSessionManager的行为之 Date getStartTimestamp(SessionKey key);
我们先来看DelegatingSession的构造方法,DelegatingSession构造时注入了NativeSessionManager和SessionKey
public DelegatingSession(NativeSessionManager sessionManager, SessionKey key) { if (sessionManager == null) { throw new IllegalArgumentException("sessionManager argument cannot be null."); } if (key == null) { throw new IllegalArgumentException("sessionKey argument cannot be null."); } if (key.getSessionId() == null) { String msg = "The " + DelegatingSession.class.getName() + " implementation requires that the " + "SessionKey argument returns a non-null sessionId to support the " + "Session.getId() invocations."; throw new IllegalArgumentException(msg); } this.sessionManager = sessionManager; this.key = key; }
DelegatingSession的 getStartTimestamp()方法
public Date getStartTimestamp() { if (startTimestamp == null) { // 这件事DelegatingSession本身没有这个职能,只能交给SessionManager去做 startTimestamp = sessionManager.getStartTimestamp(key); } return startTimestamp; }
NativeSessionManager的 getStartTimestamp(SessionKey key)方法
public Date getStartTimestamp(SessionKey key) { return lookupRequiredSession(key).getStartTimestamp(); } private Session lookupRequiredSession(SessionKey key) throws SessionException { // 参见上述,根据Session的key获得Session(如去Redis介质中查找),并不像getSession(SessionKey key)那样对Session进行包装 Session session = lookupSession(key); if (session == null) { String msg = "Unable to locate required Session instance based on SessionKey [" + key + "]."; throw new UnknownSessionException(msg); } return session; }
SimpleSession中具备了关乎于Session的各种信息他的 getStartTimestamp()方法
public Date getStartTimestamp() { return startTimestamp; }