7.SessionManager(session生命周期管理)

SessionManager负责管理shiro自己封装的session的生命周期。
为什么shiro要自己封装session?
1.可以为任意应用提供session支持,不依赖于底层容器
2.简单扩容session管理容器,可以实现任何数据源(redis,ehcache)来管理session,而不必担心jvm内存溢出

这里写图片描述
1.SessionManager

public interface SessionManager {

    //根据指定的上下文SessionContext交由SessionFactory初始化个新的session
    Session start(SessionContext context);

    //根据指定的上下文信息(SessonId..)获取一个session,如果不存在返回null,如果存在但是失效,则抛出异常SessionException
    Session getSession(SessionKey key) throws SessionException;
}

2.AbstractSessionManager

/**AbstractSessionManager是SessionManager的顶层抽象类,主要提供Session存活时间管理的支持,
默认session存活时间是30分钟

deprecate this class (see SHIRO-240):
这个类主要为子类提供一个常用的属性“globalSessionTimeout”的支持,最初设计是为ServletContainerSessionManager
和AbstractNativeSessionManager提供session存活时间管理支持,但是ServletContainerSessionManager的实现并没有
使用该“globalSessionTimeout”,这意味着只有AbstractNativeSessionManager需要使用。所以该类没有存在必要了。
https://issues.apache.org/jira/browse/SHIRO-240
**/
public abstract class AbstractSessionManager implements SessionManager {

    protected static final long MILLIS_PER_SECOND = 1000;
    protected static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
    protected static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;

    /**
     * Default main session timeout value, equal to {@code 30} minutes.
     */
    public static final long DEFAULT_GLOBAL_SESSION_TIMEOUT = 30 * MILLIS_PER_MINUTE;
    //默认为30分钟
    private long globalSessionTimeout = DEFAULT_GLOBAL_SESSION_TIMEOUT;

    public AbstractSessionManager() {
    }


    public long getGlobalSessionTimeout() {
        return this.globalSessionTimeout;
    }

    //覆盖默认session存活时间30分钟
    public void setGlobalSessionTimeout(long globalSessionTimeout) {
        this.globalSessionTimeout = globalSessionTimeout;
    }
}

3.AbstractNativeSessionManager

/**
该类基础父类AbstractSessionManager和实现NativeSessionManager接口(session操作方法规范),提供
session的start、stop、Expiration状态的触发通知。
**/
public abstract class AbstractNativeSessionManager extends AbstractSessionManager implements NativeSessionManager {

    private static final Logger log = LoggerFactory.getLogger(AbstractSessionManager.class);
    //SESSION状态的触发通知(start、stop、Expiration)
    private Collection<SessionListener> listeners;

    public AbstractNativeSessionManager() {
        this.listeners = new ArrayList<SessionListener>();
    }

    public void setSessionListeners(Collection<SessionListener> listeners) {
        this.listeners = listeners != null ? listeners : new ArrayList<SessionListener>();
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public Collection<SessionListener> getSessionListeners() {
        return this.listeners;
    }
    //实现SessionManager接口的start方法
    public Session start(SessionContext context) {
        //创建session
        Session session = createSession(context);
    //设置session过期时间
        applyGlobalSessionTimeout(session);
    //模板方法,子类对创建session后作出反应
        onStart(session, context);
    //创建session成功,迭代SessionListener执行onStart通知
        notifyStart(session);
        //返回一个包装过客户端层session,
        return createExposedSession(session, context);
    }

    //根据上下文SessionContext创建Session,返回的session需要持久化状态,方便以后获取使用
    protected abstract Session createSession(SessionContext context) throws AuthorizationException;
    //设置session过期时间
    protected void applyGlobalSessionTimeout(Session session) {
        session.setTimeout(getGlobalSessionTimeout());
    //session改变模板方法,子类对session改变作出反应。如:保存改变后的session
        onChange(session);
    }

    //模板方法:子类对session start后作出反应
    protected void onStart(Session session, SessionContext context) {
    }
    //根据sessionKey获取Session
    public Session getSession(SessionKey key) throws SessionException {
        Session session = lookupSession(key);
        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);
    }
    //获取session,如果session为null则抛异常UnknownSessionException
    private Session lookupRequiredSession(SessionKey key) throws SessionException {
        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;
    }
    //子类实现抽象方法根据sessonKey获取session
    protected abstract Session doGetSession(SessionKey key) throws InvalidSessionException;
    //封装返回客户端层session
    protected Session createExposedSession(Session session, SessionContext context) {
        return new DelegatingSession(this, new DefaultSessionKey(session.getId()));
    }
    //封装返回客户端层session
    protected Session createExposedSession(Session session, SessionKey key) {
        return new DelegatingSession(this, new DefaultSessionKey(session.getId()));
    }

    //当session过期或者停止时,需要调用通知。再调用通知前先包装下session为不可变session,防止SessionListener修改
    protected Session beforeInvalidNotification(Session session) {
        //ImmutableProxiedSession的实现即对session凡是有修改意向的方法进行重写为抛异常。
        return new ImmutableProxiedSession(session);
    }

    //session start创建后调用SessionListener的onStart通知
    protected void notifyStart(Session session) {
        for (SessionListener listener : this.listeners) {
            listener.onStart(session);
        }
    }
    //session stop后调用SessionListener的onStop通知
    protected void notifyStop(Session session) {
        Session forNotification = beforeInvalidNotification(session);
        for (SessionListener listener : this.listeners) {
            listener.onStop(forNotification);
        }
    }
    //session Expiration后调用SessionListener的onExpiration通知
    protected void notifyExpiration(Session session) {
        Session forNotification = beforeInvalidNotification(session);
        for (SessionListener listener : this.listeners) {
            listener.onExpiration(forNotification);
        }
    }
    //根据sessionKey 获取session的创建时间
    public Date getStartTimestamp(SessionKey key) {
        return lookupRequiredSession(key).getStartTimestamp();
    }
    //根据sessionKey 获取session最后访问时间
    public Date getLastAccessTime(SessionKey key) {
        return lookupRequiredSession(key).getLastAccessTime();
    }
    //根据sessionKey 获取session过期时间.  负数:则永远不过期 正数:毫秒内有效
    public long getTimeout(SessionKey key) throws InvalidSessionException {
        return lookupRequiredSession(key).getTimeout();
    }
    //根据sessionKey设置session过期时间
    public void setTimeout(SessionKey key, long maxIdleTimeInMillis) throws InvalidSessionException {
        Session s = lookupRequiredSession(key);
        s.setTimeout(maxIdleTimeInMillis);
        onChange(s);
    }
    //根据sessionKey修改session最后访问时间
    public void touch(SessionKey key) throws InvalidSessionException {
        Session s = lookupRequiredSession(key);
        s.touch();
        onChange(s);
    }
    //根据sessionKey获取session 访问IP..
    public String getHost(SessionKey key) {
        return lookupRequiredSession(key).getHost();
    }
    //根据sessionKey 获取session里的设置的属性
    public Collection<Object> getAttributeKeys(SessionKey key) {
        Collection<Object> c = lookupRequiredSession(key).getAttributeKeys();
        if (!CollectionUtils.isEmpty(c)) {
        //如果不为空,则返回个不可修改的属性集合
            return Collections.unmodifiableCollection(c);
        }
        return Collections.emptySet();
    }
    //根据sessionKey和属性key获取值
    public Object getAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException {
        return lookupRequiredSession(sessionKey).getAttribute(attributeKey);
    }
    //根据sessionKey、属性key、属性value设置属性值
    public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) throws InvalidSessionException {
        if (value == null) {
            removeAttribute(sessionKey, attributeKey);
        } else {
            Session s = lookupRequiredSession(sessionKey);
            s.setAttribute(attributeKey, value);
        //session改变模板方法,子类对session改变作出反应。如:保存改变后的session
            onChange(s);
        }
    }
    //删除session属性值
    public Object removeAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException {
        Session s = lookupRequiredSession(sessionKey);
        Object removed = s.removeAttribute(attributeKey);
        if (removed != null) {
            //session改变模板方法,子类对session改变作出反应。如:保存改变后的session
            onChange(s);
        }
        return removed;
    }
    //判断session是否过期
    public boolean isValid(SessionKey key) {
        try {
        //检查session是否过期
            checkValid(key);
            return true;
        } catch (InvalidSessionException e) {
            return false;
        }
    }
    //停止该session
    public void stop(SessionKey key) throws InvalidSessionException {
        Session session = lookupRequiredSession(key);
        try {
            if (log.isDebugEnabled()) {
                log.debug("Stopping session with id [" + session.getId() + "]");
            }
            session.stop();
        //执行session 停止模板方法
            onStop(session, key);
        //执行session停止通知
            notifyStop(session);
        } finally {
            afterStopped(session);
        }
    }
    //session停止模板方法
    protected void onStop(Session session, SessionKey key) {
        onStop(session);
    }
    //修改session停止后的状态
    protected void onStop(Session session) {

        onChange(session);
    }
    //在session停止后执行该方法。如:删除session
    protected void afterStopped(Session session) {
    }
    //检查session是否有效,即获取一个非null,非过期的session
    public void checkValid(SessionKey key) throws InvalidSessionException {
        //just try to acquire it.  If there is a problem, an exception will be thrown:
        lookupRequiredSession(key);
    }
    //对session修改作出反应的模板方法
    protected void onChange(Session s) {
    }
}

4.AbstractValidatingSessionManager

/**
AbstractValidatingSessionManager继承于AbstractNativeSessionManager且实现了ValidatingSessionManager接口,该抽象类
主要提供session验证和过期session检测。

**/
public abstract class AbstractValidatingSessionManager extends AbstractNativeSessionManager
        implements ValidatingSessionManager, Destroyable {



    private static final Logger log = LoggerFactory.getLogger(AbstractValidatingSessionManager.class);

    //默认每小时检测一次
    public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = MILLIS_PER_HOUR;
    //是否开启session验证检测
    protected boolean sessionValidationSchedulerEnabled;

    //该接口主要代理SessionManager.validateSessions()方法,定时对session验证检测。如:过期的session则销毁等
    protected SessionValidationScheduler sessionValidationScheduler;
    //该属性是定义多长时间检测一次,这个值需要根据用户的实际情况来选择,定义的太小,则检测频繁对系统性能有影响.
    protected long sessionValidationInterval;

    public AbstractValidatingSessionManager() {
        //默认开启检测
        this.sessionValidationSchedulerEnabled = true;
    //默认每小时检测一次
        this.sessionValidationInterval = DEFAULT_SESSION_VALIDATION_INTERVAL;
    }

    public boolean isSessionValidationSchedulerEnabled() {
        return sessionValidationSchedulerEnabled;
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public void setSessionValidationSchedulerEnabled(boolean sessionValidationSchedulerEnabled) {
        this.sessionValidationSchedulerEnabled = sessionValidationSchedulerEnabled;
    }

    public void setSessionValidationScheduler(SessionValidationScheduler sessionValidationScheduler) {
        this.sessionValidationScheduler = sessionValidationScheduler;
    }

    public SessionValidationScheduler getSessionValidationScheduler() {
        return sessionValidationScheduler;
    }
    //确保sessionValidation功能是开启的且有效的
    private void enableSessionValidationIfNecessary() {
        SessionValidationScheduler scheduler = getSessionValidationScheduler();
    //如果该类允许sessionValidation功能开启且scheduler无效的,则执行enableSessionValidation创建SessionValidationScheduler
        if (isSessionValidationSchedulerEnabled() && (scheduler == null || !scheduler.isEnabled())) {
            enableSessionValidation();
        }
    }


    public void setSessionValidationInterval(long sessionValidationInterval) {
        this.sessionValidationInterval = sessionValidationInterval;
    }

    public long getSessionValidationInterval() {
        return sessionValidationInterval;
    }

    @Override
    protected final Session doGetSession(final SessionKey key) throws InvalidSessionException {
        //这里我觉得会有并发问题,导致创建scheduler多次,且实现方式有问题,为什么要在使用session的地方确保每次都开启呢?
        enableSessionValidationIfNecessary();

        log.trace("Attempting to retrieve session with key {}", key);
    //根据sessionKey获取session
        Session s = retrieveSession(key);
    //如果session不为null,则检测session是否有效的
        if (s != null) {
            validate(s, key);
        }
        return s;
    }

    //根据sessionKey获取session
    protected abstract Session retrieveSession(SessionKey key) throws UnknownSessionException;

    protected Session createSession(SessionContext context) throws AuthorizationException {
        enableSessionValidationIfNecessary();
        return doCreateSession(context);
    }
    //子类实现创建session
    protected abstract Session doCreateSession(SessionContext initData) throws AuthorizationException;
    //验证session
    protected void validate(Session session, SessionKey key) throws InvalidSessionException {
        try {
            doValidate(session);
        } catch (ExpiredSessionException ese) {
        //session过期异常
            onExpiration(session, ese, key);
            throw ese;
        } catch (InvalidSessionException ise) {
        //session停止无效异常
            onInvalidation(session, ise, key);
            throw ise;
        }
    }
    //处理过期session
    protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
        log.trace("Session with id [{}] has expired.", s.getId());
        try {

            onExpiration(s);
        //session过期通知
            notifyExpiration(s);
        } finally {
        //最后处理过期session。如:删除session
            afterExpired(s);
        }
    }

    protected void onExpiration(Session session) {
        onChange(session);
    }

    protected void afterExpired(Session session) {
    }
    //处理无效session
    protected void onInvalidation(Session s, InvalidSessionException ise, SessionKey key) {
        if (ise instanceof ExpiredSessionException) {
            onExpiration(s, (ExpiredSessionException) ise, key);
            return;
        }
        log.trace("Session with id [{}] is invalid.", s.getId());
        try {
        //对停止session作出处理:如:设置停止时间为最后访问时间
            onStop(s);
        //调用session停止通知
            notifyStop(s);
        } finally {
        //session停止后作出处理,如:删除session
            afterStopped(s);
        }
    }
    //执行session的验证机制,实则交由session自己的validate();
    protected void doValidate(Session session) throws InvalidSessionException {
        if (session instanceof ValidatingSession) {
            ((ValidatingSession) session).validate();
        } else {
            String msg = "The " + getClass().getName() + " implementation only supports validating " +
                    "Session implementations of the " + ValidatingSession.class.getName() + " interface.  " +
                    "Please either implement this interface in your session implementation or override the " +
                    AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation.";
            throw new IllegalStateException(msg);
        }
    }

    /**
     * 这我也搞不懂干嘛的。。
     * Subclass template hook in case per-session timeout is not based on
     * {@link org.apache.shiro.session.Session#getTimeout()}.
     * <p/>
     * <p>This implementation merely returns {@link org.apache.shiro.session.Session#getTimeout()}</p>
     *
     * @param session the session for which to determine session timeout.
     * @return the time in milliseconds the specified session may remain idle before expiring.
     */
    protected long getTimeout(Session session) {
        return session.getTimeout();
    }

    //确保sessionValidation有效
    protected void enableSessionValidation() {
        SessionValidationScheduler scheduler = getSessionValidationScheduler();
        if (scheduler == null) {
        //如果为null。则创建个新的SessionValidationScheduler且设置到this.SessionValidationScheduler
            scheduler = createSessionValidationScheduler();
            setSessionValidationScheduler(scheduler);
        }
        if (log.isInfoEnabled()) {
            log.info("Enabling session validation scheduler...");
        }
    //启动SessionValidationScheduler里的验证机制
        scheduler.enableSessionValidation();
    //开启session验证后可以作出你的逻辑处理。目前shiro没有实现任何功能,你可根据你需求来决定。
    //如:记录每次开启时间
        afterSessionValidationEnabled();
    }
    //创建SessionValidationScheduler
    protected SessionValidationScheduler createSessionValidationScheduler() {
        ExecutorServiceSessionValidationScheduler scheduler;

        if (log.isDebugEnabled()) {
            log.debug("No sessionValidationScheduler set.  Attempting to create default instance.");
        }
    //创建ExecutorServiceSessionValidationScheduler且设置本实例进去,因为scheduler需要代理本实例的validateSessions
        scheduler = new ExecutorServiceSessionValidationScheduler(this);
        scheduler.setInterval(getSessionValidationInterval());
        if (log.isTraceEnabled()) {
            log.trace("Created default SessionValidationScheduler instance of type [" + scheduler.getClass().getName() + "].");
        }
        return scheduler;
    }



    protected void afterSessionValidationEnabled() {
    }
    //销毁SessionValidation
    protected void disableSessionValidation() {
        beforeSessionValidationDisabled();
        SessionValidationScheduler scheduler = getSessionValidationScheduler();
        if (scheduler != null) {
            try {
            //先执行SessionValidationScheduler自己的disableSessionValidation
                scheduler.disableSessionValidation();
                if (log.isInfoEnabled()) {
                    log.info("Disabled session validation scheduler.");
                }
            } catch (Exception e) {
                if (log.isDebugEnabled()) {
                    String msg = "Unable to disable SessionValidationScheduler.  Ignoring (shutting down)...";
                    log.debug(msg, e);
                }
            }
            LifecycleUtils.destroy(scheduler);
        //设置this.SessionValidationScheduler为null
            setSessionValidationScheduler(null);
        }
    }

    protected void beforeSessionValidationDisabled() {
    }

    public void destroy() {
        disableSessionValidation();
    }

    //所有session真正的检测验证逻辑
    public void validateSessions() {
        if (log.isInfoEnabled()) {
            log.info("Validating all active sessions...");
        }
        //用来记录当前这一批次检验到session过期或者无效的总数
        int invalidCount = 0;
        //获取sessionDAO中当前所有存在session,包括无效、过期的
        Collection<Session> activeSessions = getActiveSessions();
        /**
        当你用户量如果非常大时候,假如有1亿个session,那么迭代会花很长时间且在这一阶段里会影响性能.可以分批次
    **/
        if (activeSessions != null && !activeSessions.isEmpty()) {
            for (Session s : activeSessions) {
                try {
                    //simulate a lookup key to satisfy the method signature.
                    //this could probably stand to be cleaned up in future versions:
                    SessionKey key = new DefaultSessionKey(s.getId());
            //验证session
                    validate(s, key);
                } catch (InvalidSessionException e) {
                    if (log.isDebugEnabled()) {
                        boolean expired = (e instanceof ExpiredSessionException);
                        String msg = "Invalidated session with id [" + s.getId() + "]" +
                                (expired ? " (expired)" : " (stopped)");
                        log.debug(msg);
                    }
                    invalidCount++;
                }
            }
        }

        if (log.isInfoEnabled()) {
            String msg = "Finished session validation.";
            if (invalidCount > 0) {
                msg += "  [" + invalidCount + "] sessions were stopped.";
            } else {
                msg += "  No sessions were stopped.";
            }
            log.info(msg);
        }
    }
    //获取sessionDAO中当前所有存在session,包括无效、过期的
    protected abstract Collection<Session> getActiveSessions();
}

5.DefaultSessionManager

/**
DefaultSessionManager继承AbstractValidatingSessionManager且实现CacheManagerAware接口,
该具体实现类实现缓存接口CacheManagerAware只是为了让SessionDAO使用。
所有关于session的状态的改变都是交由DefaultSessionManager的sessionDAO处理。
**/
public class DefaultSessionManager extends AbstractValidatingSessionManager implements CacheManagerAware {

    private static final Logger log = LoggerFactory.getLogger(DefaultSessionManager.class);
    //SessionFactory用来根据上下文创建新session
    private SessionFactory sessionFactory;
    //SessionDAO实现了缓存机制,所以用户只要实现第三方缓存,不依赖于JVM,就不必担心session过多导致内存溢出
    protected SessionDAO sessionDAO;  //todo - move SessionDAO up to AbstractValidatingSessionManager?
    //缓存管理器
    private CacheManager cacheManager;
    /**
    是否删除session,如果session过期或者无效后。但是有些系统需要获取及时过期或者无效的SESSION。
    默认为true。如果设置为false,需要用户自己有办法在外部去管理过期或者无效session
    **/
    private boolean deleteInvalidSessions;

    public DefaultSessionManager() {
        this.deleteInvalidSessions = true;
        this.sessionFactory = new SimpleSessionFactory();
        this.sessionDAO = new MemorySessionDAO();
    }

    public void setSessionDAO(SessionDAO sessionDAO) {
        this.sessionDAO = sessionDAO;
    //设置CacheManager到SessionDAO
        applyCacheManagerToSessionDAO();
    }

    public SessionDAO getSessionDAO() {
        return this.sessionDAO;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }


    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    //session过期或者无效后是否删除
    public boolean isDeleteInvalidSessions() {
        return deleteInvalidSessions;
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public void setDeleteInvalidSessions(boolean deleteInvalidSessions) {
        this.deleteInvalidSessions = deleteInvalidSessions;
    }
    //设置缓存管理器
    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    //设置缓存管理器到SessionDAO
        applyCacheManagerToSessionDAO();
    }


    private void applyCacheManagerToSessionDAO() {
        //如果缓存管理器和SessionDAO都不null,且SessionDAO实现了CacheManagerAware,则设置CacheManager到SessionDAO
        if (this.cacheManager != null && this.sessionDAO != null && this.sessionDAO instanceof CacheManagerAware) {
            ((CacheManagerAware) this.sessionDAO).setCacheManager(this.cacheManager);
        }
    }

    //根据session上下文SessionContext创建Session
    protected Session doCreateSession(SessionContext context) {
        //调用SessionFactory创建session
        Session s = newSessionInstance(context);
        if (log.isTraceEnabled()) {
            log.trace("Creating session for host {}", s.getHost());
        }
    //保存session到SessionDAO
        create(s);
        return s;
    }
    //调用SessionFactory创建session
    protected Session newSessionInstance(SessionContext context) {
        return getSessionFactory().createSession(context);
    }

    //保存session到SessionDAO
    protected void create(Session session) {
        if (log.isDebugEnabled()) {
            log.debug("Creating new EIS record for new session instance [" + session + "]");
        }
        sessionDAO.create(session);
    }

    @Override
    protected void onStop(Session session) {
        if (session instanceof SimpleSession) {
            SimpleSession ss = (SimpleSession) session;
            Date stopTs = ss.getStopTimestamp();
            ss.setLastAccessTime(stopTs);
        }
        onChange(session);
    }

    @Override
    protected void afterStopped(Session session) {
        if (isDeleteInvalidSessions()) {
            delete(session);
        }
    }

    protected void onExpiration(Session session) {
        if (session instanceof SimpleSession) {
            ((SimpleSession) session).setExpired(true);
        }
        onChange(session);
    }

    @Override
    protected void afterExpired(Session session) {
        if (isDeleteInvalidSessions()) {
            delete(session);
        }
    }

    protected void onChange(Session session) {
        sessionDAO.update(session);
    }

    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        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;
        }
    //根据sessionID从SessionDAO中获取相对应的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;
    }
    //获取sessionKey里的SessionID
    protected Serializable getSessionId(SessionKey sessionKey) {
        return sessionKey.getSessionId();
    }
    //根据sessionID从SessionDAO中获取相对应的Session
    protected Session retrieveSessionFromDataSource(Serializable sessionId) throws UnknownSessionException {
        return sessionDAO.readSession(sessionId);
    }
    //删除session
    protected void delete(Session session) {
        sessionDAO.delete(session);
    }
    //获取SessionDAO的存在session
    protected Collection<Session> getActiveSessions() {
        Collection<Session> active = sessionDAO.getActiveSessions();
        return active != null ? active : Collections.<Session>emptySet();
    }

}

6.DefaultWebSessionManager

//基于WEB的SessionManager的实现  
public class DefaultWebSessionManager extends DefaultSessionManager implements WebSessionManager {

    private static final Logger log = LoggerFactory.getLogger(DefaultWebSessionManager.class);
    //Cookie基本模板
    private Cookie sessionIdCookie;
    //是否存储sessionID到cookie中,默认没有设置存活时间,即保存在浏览器开辟的内存中,没有持久化在硬盘上
    private boolean sessionIdCookieEnabled;

    public DefaultWebSessionManager() {
        Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
    //HttpOnly是防止用户通过js脚本获取cookie
        cookie.setHttpOnly(true); //more secure, protects against XSS attacks
        this.sessionIdCookie = cookie;
    //默认允许存储sessionID到cookie中
        this.sessionIdCookieEnabled = true;
    }
    //获取模板cookie
    public Cookie getSessionIdCookie() {
        return sessionIdCookie;
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public void setSessionIdCookie(Cookie sessionIdCookie) {
        this.sessionIdCookie = sessionIdCookie;
    }

    public boolean isSessionIdCookieEnabled() {
        return sessionIdCookieEnabled;
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public void setSessionIdCookieEnabled(boolean sessionIdCookieEnabled) {
        this.sessionIdCookieEnabled = sessionIdCookieEnabled;
    }
    //存储sessionID到cookie中
    private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
        if (currentId == null) {
            String msg = "sessionId cannot be null when persisting for subsequent requests.";
            throw new IllegalArgumentException(msg);
        }
        Cookie template = getSessionIdCookie();
        Cookie cookie = new SimpleCookie(template);
        String idString = currentId.toString();
        cookie.setValue(idString);
        cookie.saveTo(request, response);
        log.trace("Set session ID cookie for session with id {}", idString);
    }
    //删除浏览器SessionID cookie
    private void removeSessionIdCookie(HttpServletRequest request, HttpServletResponse response) {
        getSessionIdCookie().removeFrom(request, response);
    }
    //根据sessionID Cookie获取sessionid
    private String getSessionIdCookieValue(ServletRequest request, ServletResponse response) {
        if (!isSessionIdCookieEnabled()) {
            log.debug("Session ID cookie is disabled - session id will not be acquired from a request cookie.");
            return null;
        }
        if (!(request instanceof HttpServletRequest)) {
            log.debug("Current request is not an HttpServletRequest - cannot get session ID cookie.  Returning null.");
            return null;
        }
        HttpServletRequest httpRequest = (HttpServletRequest) request;
    //从Cookie中读取sessionID
        return getSessionIdCookie().readValue(httpRequest, WebUtils.toHttp(response));
    }

    //该方法尝试通过多种办法获取SessionID
    private Serializable getReferencedSessionId(ServletRequest request, ServletResponse response) {
        //首先在cookie中获取sessionID
        String id = getSessionIdCookieValue(request, response);
        if (id != null) {
        //设置获取SessionID的来源 Cookie
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                    ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
        } else {
            //cookie不存在,尝试通过uri中获取
            id = getUriPathSegmentParamValue(request, ShiroHttpSession.DEFAULT_SESSION_ID_NAME);

            if (id == null) {
                //尝试中request的参数中获取
                String name = getSessionIdName();

                id = request.getParameter(name);
                if (id == null) {

                    id = request.getParameter(name.toLowerCase());
                }
            }
            if (id != null) {
        //设置获取SessionID的来源 URL
                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                        ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
            }
        }
        if (id != null) {
        //设置SessionUD 
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            //设置SessionID有效.
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
        }
        return id;
    }

    //通过URI获取SessionID
    private String getUriPathSegmentParamValue(ServletRequest servletRequest, String paramName) {

        if (!(servletRequest instanceof HttpServletRequest)) {
            return null;
        }
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        String uri = request.getRequestURI();
        if (uri == null) {
            return null;
        }

        int queryStartIndex = uri.indexOf('?');
        if (queryStartIndex >= 0) { //get rid of the query string
            uri = uri.substring(0, queryStartIndex);
        }

        int index = uri.indexOf(';'); //now check for path segment parameters:
        if (index < 0) {
            //no path segment params - return:
            return null;
        }

        //there are path segment params, let's get the last one that may exist:

        final String TOKEN = paramName + "=";

        uri = uri.substring(index+1); //uri now contains only the path segment params

        //we only care about the last JSESSIONID param:
        index = uri.lastIndexOf(TOKEN);
        if (index < 0) {
            //no segment param:
            return null;
        }

        uri = uri.substring(index + TOKEN.length());

        index = uri.indexOf(';'); //strip off any remaining segment params:
        if(index >= 0) {
            uri = uri.substring(0, index);
        }

        return uri; //what remains is the value
    }

    //获取sessionid存储的名字
    private String getSessionIdName() {
        String name = this.sessionIdCookie != null ? this.sessionIdCookie.getName() : null;
        if (name == null) {
            name = ShiroHttpSession.DEFAULT_SESSION_ID_NAME;
        }
        return name;
    }
    //封装一个基于WEB(包含request和response的支持)的 客户端层session,该方法主要用在新创建session
    protected Session createExposedSession(Session session, SessionContext context) {
        if (!WebUtils.isWeb(context)) {
            return super.createExposedSession(session, context);
        }
        ServletRequest request = WebUtils.getRequest(context);
        ServletResponse response = WebUtils.getResponse(context);
        SessionKey key = new WebSessionKey(session.getId(), request, response);
        return new DelegatingSession(this, key);
    }
    //封装一个基于WEB(包含request和response的支持)的 客户端层session,该方法主要用在获取已存在的session
    protected Session createExposedSession(Session session, SessionKey key) {
        if (!WebUtils.isWeb(key)) {
            return super.createExposedSession(session, key);
        }

        ServletRequest request = WebUtils.getRequest(key);
        ServletResponse response = WebUtils.getResponse(key);
        SessionKey sessionKey = new WebSessionKey(session.getId(), request, response);
        return new DelegatingSession(this, sessionKey);
    }

    //session start创建后保存sessionID到客户端浏览器cookie中
    @Override
    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);
    //判断是否允许存储sessionID到cookie中
        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);
    //设置session为新创建
        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
    }
    //获取sessionID
    @Override
    public Serializable getSessionId(SessionKey key) {
        Serializable id = super.getSessionId(key);
        if (id == null && WebUtils.isWeb(key)) {
        //WebSessionKey中封装着request和response
            ServletRequest request = WebUtils.getRequest(key);
            ServletResponse response = WebUtils.getResponse(key);
            id = getSessionId(request, response);
        }
        return id;
    }

     protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        return getReferencedSessionId(request, response);
    }

    @Override
    protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
        super.onExpiration(s, ese, key);
        onInvalidation(key);
    }

    @Override
    protected void onInvalidation(Session session, InvalidSessionException ise, SessionKey key) {
        super.onInvalidation(session, ise, key);
        onInvalidation(key);
    }
    //无效session后续操作
    private void onInvalidation(SessionKey key) {
        ServletRequest request = WebUtils.getRequest(key);
        if (request != null) {
            request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID);
        }
        if (WebUtils.isHttp(key)) {
            log.debug("Referenced session was invalid.  Removing session ID cookie.");
            removeSessionIdCookie(WebUtils.getHttpRequest(key), WebUtils.getHttpResponse(key));
        } else {
            log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " +
                    "pair. Session ID cookie will not be removed due to invalidated session.");
        }
    }

    @Override
    protected void onStop(Session session, SessionKey key) {
        super.onStop(session, key);
        if (WebUtils.isHttp(key)) {
            HttpServletRequest request = WebUtils.getHttpRequest(key);
            HttpServletResponse response = WebUtils.getHttpResponse(key);
            //删除sessionID cookie
            removeSessionIdCookie(request, response);
        } else {
            log.debug("SessionKey argument is not HTTP compatible or does not have an HTTP request/response " +
                    "pair. Session ID cookie will not be removed due to stopped session.");
        }
    }

    //用于判断是否使用serlvet的session
    public boolean isServletContainerSessions() {
        return false;
    }
}
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值