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;
}
原文地址:https://www.cnblogs.com/BINGJJFLY/p/9267352.html