【问题标题】:Guice @SessionScoped annotation causes IllegalArgumentException with Shiro HttpSessionGuice @SessionScoped 注释导致 IllegalArgumentException 与 Shiro HttpSession
【发布时间】:2013-12-11 11:13:38
【问题描述】:

我有一个 Apache Wicket 1.5 应用程序,它使用 Shiro 来保证安全性,并使用 Guice 来进行依赖注入。 它的大部分页面都是无状态的,但我的一些模型对象(用户数据、当前菜单状态……)需要在同一会话中的所有请求中保持一致。所有这些对象都有逻辑(主要是使用远程 EJB3 接口访问数据库的简单查找器方法)和状态,并且都实现了 Serializable。

这里有一个简短的摘录应该传达这个想法:

@SessionScoped
public class UsersImpl implements Users, Serializable {

    private static final long serialVersionUID = 8841809043461673585L;
    private final Logger log = LoggerFactory.getLogger( UsersImpl.class );

    @Inject
    public UserService users;

    @Inject
    public RoleService roles;

    private UserDTO currentUser;

    public UserVO findUserByUser( UserVO user ) {
        UserDTO userDto = null;
        try {
            userDto = users.findUserByUser( user.toUserDTO() );
        } catch( Exception e ) {
            log.error( "Error finding user:"+user.id, e );
        }
        return userDto != null ? new UserVO( userDto ) : null;
    }

(...)

}

我使用@Singleton(为简单起见)开发和单元测试了这些类,并且一切正常,但是我经常遇到这样的错误,现在我已经切换到@SessionScoped进行生产:

Guice provision errors:
1) Error in custom provider, org.apache.shiro.session.InvalidSessionException:
   java.lang.IllegalArgumentException: 
   HttpSession based implementations of the Shiro Session interface requires attribute keys to be String objects.  The HttpSession class does not support anything other than String keys.

显然,Guice 似乎使用了一些自定义的 Key 对象来存储会话中的对象,而 Shiro HttpSession 实现无法处理这一点。但奇怪的是,并非所有@SessionScoped 类都发生此异常,但肯定不止一个。

我一直在疯狂地搜索网络,寻找我能做什么的想法 - 一些强制 Guice 使用字符串作为键的方法,一些其他让 HttpSession 更兼容的方法,任何东西 - 但我似乎无法找到任何有用的信息。另外,从我对错误信息的搜索结果来看,我似乎是这个星球上唯一有这个问题的人......

有什么办法可以做到这一点吗?还是我在这里做错了什么?

【问题讨论】:

  • 如何初始化Shiro?通过安装ShiroModule?
  • 我安装了ShiroAopModule 和一个自定义的扩展ShiroWebModule 并拥有您本来可以放入shiro.ini 的所有内容。这也将SessionScoped.class 绑定到ShiroSessionScopeUsersImpl 没有单独的模块 - 接口 Users@ImplementedBy 注释。
  • 如果我使用@Singleton而不是@SessionScoped,整个设置工作正常:所有注入工作,整个应用程序运行没有错误 - 除了它仅限于单个用户,当然。

标签: java guice shiro java-ee-5 wicket-1.5


【解决方案1】:

嗯,这个问题很难回答,但我试着给你一些选择......

您的错误来自预先检查...所以,我假设您的应用程序甚至没有启动,对吧?那么您很可能使用生产阶段或急切地创建了一些绑定,并且该对象引用了Session 范围内的另一个对象,这是问题所在。因此,现在您应该将所有 SessionScope 直接注入更改为 Providers 注入,如下例所示:

你能改吗

@Inject
public UserService users;

@Inject
public Provider<UserService> userProvider; //and call userProvider.get() when you will need it?

为什么会这样?

  1. SessionScoped 对象只能在 GuiceFilter.doFilter() 中访问,因此如果您混合范围,它可能会导致某些运行时异常。特别是当您将Stage 更改为Production 或将一些单例设置为热切加载时。你可以了解更多here。混合 Scopes 时使用 Providers 是一种很好的做法

  2. 问题可能是 Subject 仅在 ShiroFilter.doFilter() check my post 内绑定。然后,如果您在外面,可以说 GuiceFilter 那时可能没有 Subject 绑定。再次尝试使用Providers

希望,会有所帮助。

【讨论】:

  • 谢谢,我会试试供应商。虽然当我调用页面时发生异常 - 应用程序启动没有问题。
  • 经过一些广泛的尝试和敲击键盘后,我想我可能已经找到了整个问题的根源:看起来它是由陈旧的依赖引起的(我使用 ehcache 2.7.4存储会话,在我的一个模块中,ehcache-core 仍然是一个更旧的版本)。现在测试整个应用程序太累了,但是fwiw:非提供者版本似乎工作正常,至少对于我在更新依赖项后所看到的情况。感谢您的帮助,我明天会有一个明确的答案。
  • 原来的错误真的消失了,现在我已经将所有依赖项更新到了最新版本。但是,您对提供商的建议 a) 帮助我走上了正确的轨道,b) 顺便解决了另一个我一直在努力解决的问题。因此,我会接受您的回答,即使它不能完全解决问题。再次感谢您的帮助!