Spring忽略了ApacheShiro领域类中的@Transactional注释

Spring忽略了ApacheShiro领域类中的@Transactional注释,spring,hibernate,shiro,Spring,Hibernate,Shiro,我正在使用Spring进行IOC和事务管理,并计划使用ApacheShiro作为安全库 每当我想检查一个用户的权限时,我都会调用subject.isPermitted(“right”),然后Shiro使用数据存储检查权限。在这些调用中,建立了数据库连接,我用@Transactional注释了该方法。但是,每当执行权限检查时,我总是收到一个错误,即没有绑定到线程的Hibernate会话 该方法位于领域类中。我定义了一个自定义Shiro领域类: @Component public class Mai

我正在使用Spring进行IOC和事务管理,并计划使用ApacheShiro作为安全库

每当我想检查一个用户的权限时,我都会调用
subject.isPermitted(“right”)
,然后Shiro使用数据存储检查权限。在这些调用中,建立了数据库连接,我用
@Transactional
注释了该方法。但是,每当执行权限检查时,我总是收到一个错误,即没有绑定到线程的Hibernate会话

该方法位于领域类中。我定义了一个自定义Shiro领域类:

@Component
public class MainRealm extends AuthorizingRealm {

@Autowired
protected SysUserDao userDao;

@Transactional
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
        throws AuthenticationException {
    ...
    final SysUser user = this.userDao.findByUsername(un);
    ...
    return authInfo;
}

@Transactional
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    ...
    permissions = this.userDao.getAccessRights(un);
    ...
    return authInfo;
}
}
Apache Shiro使用Servlet过滤器,因此我在web.xml中定义了以下内容:

<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
根据它的意思,事务管理器不会对
MainRealm
进行后处理,因此任何@Transactional注释都会被忽略。如果是,我该如何更正


编辑2根据:“换句话说,如果我编写自己的BeanPostProcessor,并且该类直接引用上下文中的其他Bean,那么这些被引用的Bean将不符合自动代理的条件,并且会记录一条这样的消息。”我刚刚检查了ShiroFilterFactoryBean,它实际上是一个BeanPostProcessor。问题是它需要一个
SecurityManager
实例,而这个实例又需要一个
MainRealm
实例。所以这两个bean都是自动连接的,因此不适合代理。我觉得我离解决方案更近了,但我仍然无法解决它。

@Transactional
注释可以在以下情况之前使用:

  • 接口定义
  • 接口方法
  • 类定义
  • 类的公共方法
正如在报告中所解释的那样


您的方法受保护这一事实肯定是您出现问题的原因,并且您的服务方法可能被声明为
公共
,这将解释为什么它在这种情况下工作

问题的根本原因实际上是由于以下原因:

所有BeanPostProcessor及其直接引用的bean将在启动时实例化。。。由于AOP自动代理是作为BeanPostProcessor本身实现的,因此没有任何BeanPostProcessor或直接引用的bean符合自动代理的条件(因此不会将方面“编织”到其中。

所以问题是

我通过将领域bean创建与SecurityManager bean创建分离,解决了这个问题

相关变更来自以下代码:

@Bean
@Autowired
public DefaultWebSecurityManager securityManager(MainRealm mainRealm) {
    final HashedCredentialsMatcher hcm = new HashedCredentialsMatcher(shiroHash);
    hcm.setHashIterations(shiroIter);
    hcm.setStoredCredentialsHexEncoded(shiroHexEncoded);
    mainRealm.setCredentialsMatcher(hcm);
    final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
    sm.setRealm(mainRealm);
    return sm;
}
@Bean
public DefaultWebSecurityManager securityManager() {
    final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
    //sm.setRealm(mainRealm); -> set this AFTER Spring initialization so no dependencies
    return sm;
}
以下代码:

@Bean
@Autowired
public DefaultWebSecurityManager securityManager(MainRealm mainRealm) {
    final HashedCredentialsMatcher hcm = new HashedCredentialsMatcher(shiroHash);
    hcm.setHashIterations(shiroIter);
    hcm.setStoredCredentialsHexEncoded(shiroHexEncoded);
    mainRealm.setCredentialsMatcher(hcm);
    final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
    sm.setRealm(mainRealm);
    return sm;
}
@Bean
public DefaultWebSecurityManager securityManager() {
    final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
    //sm.setRealm(mainRealm); -> set this AFTER Spring initialization so no dependencies
    return sm;
}
然后我使用一个ServletContextListener,它在Spring上下文初始化完成时侦听,我拥有
MainRealm
SecurityManager
bean。然后我只需将一个bean插入另一个bean中

@Override
public void contextInitialized(ServletContextEvent sce) {
    try {

        //Initialize realms
        final MainRealm mainRealm = (MainRealm)ctx.getBean("mainRealm");
        final DefaultWebSecurityManager sm = (DefaultWebSecurityManager)ctx.getBean("securityManager");
        sm.setRealm(mainRealm);
    } catch (Exception e) {
        System.out.println("Error loading: " + e.getMessage());
        throw new Error("Critical system error", e);
    }
}

您可以尝试使用
@transactional
@transactional(readOnly=true)将所有事务逻辑移动到某个
UserService
annotations并在您的
MainRealm
中使用此服务。我试图将一个服务类自动连接到我的领域,但是,在这样做时,该服务类也遇到了
无hibernate会话绑定到线程的错误,并且它的@Transactional annotations似乎不再起作用。看起来我正在做一些事情在初始化Shiro对象时使用了g。谢谢你的提示。但是,我尝试了这个方法,但没有成功。我认为这可能与我用Spring错误配置Shiro对象有关。