吃透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();
}
}