吃透Shiro源码3----Session

技术手法

(1)接口的代理

Shiro自己也实现了会话机制。Shiro创建了自己的Session接口。为了拦截某些Session调用并执行其他逻辑,创建了一个简单的Session代理。如何扩展呢?可以继承ProxiedSession这个类,重写某个function(),并调用super.function()立即调用代理对象的方法,在此之前可编写其他代码以执行其他逻辑。此实现思路可以应用到任何已经创建的接口上。

/**
 * 简单的代理Session实现
 * 立即将调用转给代理实例
 * 此类对于框架子类继承很有用,
 * 以拦截某些Session调用并执行其他逻辑。
 */
public class ProxiedSession implements Session ...
    /**
     * 代理实例
     */
    protected final Session delegate;

    /**
     * @param target 要被代理的Session对象
     */
    public ProxiedSession(Session target) {
        this.delegate = target;
    }

    @Override
    public Serializable getId() {
        //立即把方法调用转到代理实例
        return delegate.getId();
    }

(2)接口作为方法参数

方法上接收某个接口,实质上就是策略设计模式的最经典应用。下面的方法展示了如何把权限字符串解析成权限对象。此方法上接收PermissionResolver,它其实是一个接口,并且此刻还没有任何实现类出现。这样做的好处就是,我们已经把功能定义好,就差实现类。并且接口的实现可以动态切换,扩展性十足。

public interface PermissionResolver {

    /**
     * 解析权限
     *
     * @param permissionString 权限字符串
     * @return 返回权限对象
     */
    Permission resolvePermission(String permissionString);
}
public class PermissionUtils ...

    /**
     * 把权限字符串集合改成权限对象集合
     */
    public static Set<Permission> resolvePermissions(
             Collection<String> permissionStrings, 
             PermissionResolver permissionResolver) {
        Set<Permission> permissionResults = 
             new LinkedHashSet<>(permissionStrings.size());
        //使用解析器解析
        for (String permissionString : permissionStrings) {
            permissionResults.add(permissionResolver.
                  resolvePermission(permissionString));
        }
        return permissionResults;
    }

(3)生命周期的使用工具

看到了一个比较巧妙的类,帮助调用其他生命周期接口。可以参照此类的设计,以设计出控制其他实现了接口的类的调用。

public interface Initializable {
    void init() throws ShiroException;
}

public interface Destroyable {
    void destroy() throws Exception;
}
public abstract class LifecycleUtils ...

    public static void init(Object object) 
                              throws ShiroException {
        if (object instanceof Initializable) {
            init((Initializable) object);
        }
    }

    public static void init(Initializable initializable) 
                              throws ShiroException {
        if (initializable != null) {
            initializable.init();
        }
    }
public static void destroy(Object object) 
                                  throws Exception {
        if (object instanceof Destroyable) {
            destroy((Destroyable) object);
        }
    }

    public static void destroy(Destroyable destroyable)
                                  throws Exception {
        if (destroyable != null) {
            destroyable.destroy();
        }
    }

重点研究类

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;

public interface Session {


    /**
     * 返回会话创建时系统分配的唯一标识符。
     *
     * @return 可序列化的唯一标识
     */
    Serializable getId();

    /**
     * 返回会话开始的时间, 即系统创建实例的时间。
     *
     * @return 系统创建实例的时间。
     */
    Date getStartTimeStamp();


    /**
     * 返回上次调用时间
     *
     * @return 上次调用时间
     */
    Date getLastAccessTime();


    /**
     * 返回会话到期之前可能的空闲时间
     * 非负返回值(0或更大)意味着如果会话闲置将导致会话期满时间长度。
     * 负值表示会话永不过期。
     * 在Shiro会话中始终使用毫秒值。
     * HttpSession.getMaxInactiveInterval()使用秒
     *
     * @return 会话到期之前可能的空闲时间(毫秒,Shiro都用毫秒)
     * @throws InvalidSessionException
     */
    long getTimeout() throws InvalidSessionException;


    /**
     * 设置会话在到期前可能保持空闲的时间(以毫秒为单位)。
     *
     * @param maxIdleTimeInMillis 会话在到期前可能保持空闲的时间(以毫秒为单位)。
     * @throws InvalidSessionException
     */
    void setTimeout(long maxIdleTimeInMillis) throws InvalidSessionException;


    /**
     * 返回发起此会话的主机IP或者IP字符串
     *
     * @return 主机IP或者IP字符串
     */
    String getHost();


    /**
     * 把词汇化{@link #getLastAccessTime()}更新为当前时间
     * 此方法目的就是保证会话不会过期
     *
     * @throws InvalidSessionException
     */
    void touch() throws InvalidSessionException;

    /**
     * 停止此会话并释放所有关联资源
     *
     * @throws InvalidSessionException
     */
    void stop() throws InvalidSessionException;


    /**
     * 绑定键值对到会话
     *
     * @param key
     * @param value
     */
    void setAttribute(Object key, Object value);

    /**
     * 从会话获取键值对
     *
     * @param key
     * @return
     */
    Object getAttribute(Object key);


    /**
     * 解除以指定的{@code key}名称绑定到此会话的对象绑定
     *
     * @param key
     * @return
     */
    Object removeAttribute(Object key);


    /**
     * 返回此会话下存储的所有属性的键。
     *
     * @return
     * @throws InvalidSessionException
     */
    Collection<Object> getAttributeKeys() throws InvalidSessionException;
}

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;

/**
 * 简单的代理Session实现
 * 立即将调用转给代理实例
 * 此类对于框架子类继承很有用,
 * 以拦截某些Session调用并执行其他逻辑。
 */
public class ProxiedSession implements Session {

    /**
     * 代理实例
     */
    protected final Session delegate;

    /**
     * @param target 要被代理的Session对象
     */
    public ProxiedSession(Session target) {
        this.delegate = target;
    }

    @Override
    public Serializable getId() {
        return delegate.getId();
    }

    @Override
    public Date getStartTimeStamp() {
        return delegate.getStartTimeStamp();
    }

    @Override
    public Date getLastAccessTime() {
        return delegate.getLastAccessTime();
    }

    @Override
    public long getTimeout() throws InvalidSessionException {
        return delegate.getTimeout();
    }

    @Override
    public void setTimeout(long maxIdleTimeInMillis) throws InvalidSessionException {
        delegate.setTimeout(maxIdleTimeInMillis);
    }

    @Override
    public String getHost() {
        return delegate.getHost();
    }

    @Override
    public void touch() throws InvalidSessionException {
        delegate.touch();
    }

    @Override
    public void stop() throws InvalidSessionException {
        delegate.stop();
    }

    @Override
    public void setAttribute(Object key, Object value) {
        delegate.setAttribute(key, value);
    }

    @Override
    public Object getAttribute(Object key) {
        return delegate.getAttribute(key);
    }

    @Override
    public Object removeAttribute(Object key) {
        return delegate.removeAttribute(key);
    }

    @Override
    public Collection<Object> getAttributeKeys() throws InvalidSessionException {
        return delegate.getAttributeKeys();
    }
}

发布了315 篇原创文章 · 获赞 243 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/yanluandai1985/article/details/103463634