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;
}