Shiro启动时报shiroFilterFactoryBean和securityManager循环依赖

ragnar 1年前 ⋅ 172 阅读

1 现象

主要改动点:
项目引入swagger文档

环境

  • 非生产环境:
    • 打包:idea
    • 应用启动:无异常(未能复现)
  • 生产环境:
    • 打包(docker容器内):maven:3.5.4-jdk-8
    • 部署:docker
    • 应用启动:报错

截取的报错日志信息(格式化后的):

org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'webMvcObjectMapperConfigurer'
    defined in class path resource [springfox/documentation/spring/web/SpringfoxWebMvcConfiguration.class]:
    BeanPostProcessor before instantiation of bean failed;
    nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'authorizationAttributeSourceAdvisor'
    defined in class path resource [org/apache/shiro/spring/boot/autoconfigure/ShiroAnnotationProcessorAutoConfiguration.class]:
    Unsatisfied dependency expressed through method 'authorizationAttributeSourceAdvisor' parameter 0;
    nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'org.apache.shiro.spring.config.web.autoconfigure.ShiroWebAutoConfiguration':
    Unsatisfied dependency expressed through field 'rolePermissionResolver';
    nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'shiroFilterFactoryBean'
    defined in class path resource [website/ragnar/vks/configuration/ShiroConfiguration.class]:
    Unsatisfied dependency expressed through method 'shiroFilterFactoryBean' parameter 0;
    nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'securityManager':
    Requested bean is currently in creation: Is there an unresolvable circular reference?

2 分析

从上面的报错信息,我们可以得到以下线索:
有三个异常类:

  • BeanCreationException,即Bean创建异常;
  • UnsatisfiedDependencyException,即不满足依赖异常;
  • BeanCurrentlyInCreationException,即bean正在被创建异常。

猜测
那就可能是shiroFilterFactoryBeansecurityManager这两个bean可能存在循环依赖。

代码分析
应用的配置类ShiroConfiguration中定义了shiroFilterFactoryBean

@Configuration
@ConditionalOnProperty(name = "shiro.web.enabled", matchIfMissing = true)
public class ShiroConfiguration {
	// ...
    
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager) {
        // ...
    }
    
    // ...
}

securityManager即是用jar中org.apache.shiro.spring.config.web.autoconfigure.ShiroWebAutoConfiguration定义的:

@Configuration
@AutoConfigureBefore(ShiroAutoConfiguration.class)
@ConditionalOnProperty(name = "shiro.web.enabled", matchIfMissing = true)
public class ShiroWebAutoConfiguration extends AbstractShiroWebConfiguration {
	// ...
    
    @Bean
    @ConditionalOnMissingBean
    @Override
    protected SessionsSecurityManager securityManager(List<Realm> realms) {
        return super.securityManager(realms);
    }
	
    // ...
}

由以上代码可以看出,shiroFilterFactoryBeansecurityManager这两个bean没有直接的依赖关系。

间接依赖关系?
报错信息中有这样一个叫rolePermissionResolver的bean,在ShiroWebAutoConfiguration的父父类AbstractShiroConfiguration中定义为成员变量,代码如下:

public class AbstractShiroConfiguration {

    // ...

    @Autowired(required = false)
    protected RolePermissionResolver rolePermissionResolver;
    
    // ...
}

这里并没有强制要求依赖注入,但为什么会抛出UnsatisfiedDependencyException

3 解决方案

根据上面分析,基本可以推断,shiroFilterFactoryBeansecurityManager之间应该是存在间接性的循环依赖。
所以方案就是:采用懒加载方式
ShiroFilterFactoryBean的@Bean上面加上@Lazy注解,be like:

	@Lazy
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager) {
        // ...
    }

4 总结

  • **编译打包环境要尽可能一致。**这环境上主要差别应该就在打包上了,因为下载来自生产环境的jar包能复现这个报错。
  • **运行原理要尽可能了解和熟悉。**生产环境是基于gitlab做的自动化部署,当时是参考一些文档写的gitlab自动部署脚本,对其原理还不算了解。

全部评论: 0

    我有话说:

    目录