1.web.xm中添加<distributable />不行,参考http://cloudbbs.org/forum.php?mod=viewthread&tid=5420&page=1#pid32516
2.开启memcache也不行
3.自定义shiro的sessionManager不行,参考 http://cloudbbs.org/forum.php?mod=viewthread& ;tid=12905
4.自定义shiro的sessionDao还是不行,参考 http://cloudbbs.org/forum.php?mod=viewthread& ;tid=12678
然后各种方法组合,疯了,还是没成功,实际上我就用了一个jvm,不关分布式session的问题。网上发现还是有好些人遇到了同样的问题,但是和shiro相关的帖子都没有成功的解决方法。于是我详细看了段时间shiro的源码,终于让我给发现问题所在,顺利解决,这里贴出来,希望对大家有用。
shiro自己实现了servlet标准,其中org.apache.shiro.web.servlet.ShiroHttpServletRequest继承自javax.servlet.http.HttpServletRequestWrapper,对getSession()等方法做了重写,问题出在这了,shiro的web fileter中有一个org.apache.shiro.web.servlet.AbstractShiroFilter,其他实现filter全部继承自这个类,
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain)
throws ServletException, IOException {
Throwable t = null;
try {
final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
final Subject subject = createSubject(request, response);
//noinspection unchecked
subject.execute(new Callable() {
public Object call() throws Exception {
updateSessionLastAccessTime(request, response);
executeChain(request, response, chain);
return null;
}
});
} catch (ExecutionException ex) {
t = ex.getCause();
} catch (Throwable throwable) {
t = throwable;
}
if (t != null) {
if (t instanceof ServletException) {
throw (ServletException) t;
}
if (t instanceof IOException) {
throw (IOException) t;
}
//otherwise it's not one of the two exceptions expected by the filter method signature - wrap it in one:
String msg = "Filtered request failed.";
throw new ServletException(msg, t);
}
}
问题就在上面红色部分,shiro用servletRequest创建了ShiroHttpServletRequest实例request,最后又将request传递给过滤链 executeChain(request, response, chain);过滤链调用一个filter传递的已经变成ShiroHttpServletRequest了,最终servlet容器中的request也变成ShiroHttpServletRequest了,sae应该也继承HttpServletRequest对获取session的方法进行了处理比方说缓存,导致了一些不可预料的错误,如session.getId()==null;稍微修改这个类方法,就好了:
protected void doFilterInternal(final ServletRequest servletRequest,final ServletResponse servletResponse, final FilterChain chain)
throws ServletException, IOException {
Throwable t = null;
try {
final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
final Subject subject = createSubject(request, response);
//noinspection unchecked
subject.execute(new Callable() {
public Object call() throws Exception {
updateSessionLastAccessTime(request, response);
executeChain(servletRequest, servletResponse, chain);
return null;
}
});
} catch (ExecutionException ex) {
t = ex.getCause();
} catch (Throwable throwable) {
t = throwable;
}
if (t != null) {
if (t instanceof ServletException) {
throw (ServletException) t;
}
if (t instanceof IOException) {
throw (IOException) t;
}
//otherwise it's not one of the two exceptions expected by the filter method signature - wrap it in one:
String msg = "Filtered request failed.";
throw new ServletException(msg, t);
}
}