• SpringBoot整合shiro-spring-boot-starterqi


    1、项目启动时报错如下:

     

    1. Description:
    2. The bean 'securityManager', defined in class path resource [org/apache/shiro/spring/config/web/autoconfigure/ShiroWebAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [com/ncwu/common/infrastructure/config/ShiroConfig.class] and overriding is disabled.
    3. Action:
    4. Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

     2、原因分析

          我的自定义ShiroConfig配置类中添加的安全管理器,代码如下:

    1. @Bean
    2. public SecurityManager securityManager(JwtRealm jwtRealm) {
    3. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    4. //配置realm
    5. securityManager.setRealm(jwtRealm);
    6. return securityManager;
    7. }

          根据异常信息查看ShiroWebAutoConfiguration源码时发现其中已经定义了securityManager方法,我们在ShiroConfig配置类中再次定义securityManager方法,因返回的类与其不一样导致出错,ShiroWebAutoConfiguration类中定义的securityManager方法代码如下:

    1. @Bean
    2. @ConditionalOnMissingBean
    3. @Override
    4. protected SessionsSecurityManager securityManager(List realms) {
    5. return super.securityManager(realms);
    6. }

          下面这些为补充知识:我们都知道@ConditionalOnBean作用是根据value属性按bean的类型或则bean的名称判断它的实例对象是否在IOC容器中,如果存在返回true,否则返回false。而@ConditionalOnMissingBean的作用与@ConditionalOnBean相反。如果@ConditionalOnBean和@ConditionalOnMissingBean这两个注解没有参数,那这两个注解以何种方式来判断呢?在Spring Boot官方文档中找出了答案。

          意思是:在@ConditionalOnMissingBean没有参数的情况下,目标类型默认为方法的返回类型,如果IOC容器中没有类型为SomeService及其子类的实例对象,则将创建 someService bean。

          从源代码中可以看出@ConditionalOnMissingBean没有参数,那么如果IOC容器中没有类型为SessionsSecurityManager及其子类的实例对象,那么该方法则会执行,并且源码securityManager方法返回的是SessionsSecurityManager,而自己定义的ShiroConfig中返回的是SecurityManager(因为@Bean注解会指定改bean的类型为该方法的返回类型),所以它会判断出IOC容器中没有类型为SessionsSecurityManager及其子类的实例对象,源码中的方法执行,故IOC容器中有两个名为securityManager的Bean,因而报错。所以如果要自定义securityManager方法,返回类型只能是SessionsSecurityManager及其子类,而SessionsSecurityManager的子类是DefaultSecurityManager,DefaultWebSecurityManager又继承DefaultSecurityManager,相关类图如下:

          故而正确的代码应该是:

    1. @Bean
    2. public SessionsSecurityManager securityManager(JwtRealm jwtRealm) {
    3. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    4. //配置realm
    5. securityManager.setRealm(jwtRealm);
    6. return securityManager;
    7. }
    8. //或者如下,将方法返回类型改为DefaultWebSecurityManager
    9. /*@Bean
    10. public DefaultWebSecurityManager securityManager(JwtRealm jwtRealm) {
    11. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    12. //配置realm
    13. securityManager.setRealm(jwtRealm);
    14. return securityManager;
    15. }*/

    3、测试@ConditionalOnMissingBean注解

    新建下面3个类:

    1. //动物
    2. @Data
    3. public class Animal {
    4. private String name;
    5. private Integer age;
    6. }
    7. //狗
    8. @EqualsAndHashCode(callSuper = true)
    9. @Data
    10. public class Dog extends Animal {
    11. private String type;
    12. }
    13. //二哈
    14. @EqualsAndHashCode(callSuper = true)
    15. @Data
    16. public class TwoHa extends Dog {
    17. private String a;
    18. }

    启动类:

    1. @SpringBootApplication
    2. //扫描下面的接口生成代理实现类
    3. @MapperScan("com.ncwu.**.domain.mapper")
    4. public class ShiroApplication {
    5. public static void main(String[] args) {
    6. SpringApplication.run(ShiroApplication.class, args);
    7. }
    8. //若IOC容器中没有Animal类型及其子类Dog类型的实例对象时,该方法才会执行
    9. @Bean
    10. @ConditionalOnMissingBean
    11. public Animal twoHa(JwtRealm realm) {
    12. TwoHa twoHa = new TwoHa();
    13. twoHa.setType("twoHa1");
    14. twoHa.setAge(10);
    15. twoHa.setName("twoHa1");
    16. return twoHa;
    17. }
    18. @Bean
    19. public Dog twoHa() {
    20. TwoHa twoHa = new TwoHa();
    21. twoHa.setType("twoHa2");
    22. twoHa.setAge(20);
    23. twoHa.setName("twoHa2");
    24. return twoHa;
    25. }
    26. }

    测试类:

    1. @RunWith(SpringRunner.class)
    2. @SpringBootTest(classes = ShiroApplication.class)
    3. public class TestDao {
    4. @Autowired
    5. private ApplicationContext appContext;
    6. @Test
    7. public void test() throws Exception{
    8. /*String[] beanNamesForType = appContext.getBeanNamesForType(Animal.class);
    9. for (String s : beanNamesForType) {
    10. System.out.println(s);
    11. }*/
    12. appContext.getBean(Animal.class);
    13. //appContext.getBean("dog");
    14. }
    15. }

    测试结果:


     

  • 相关阅读:
    熵-条件熵-联合熵-互信息-交叉熵
    neo4j4.0+与JDK11知识图谱安装与配置
    CSS:text-decoration文本装饰
    中小企业如何最大程度地利用CRM系统的潜力?
    C语言学生宿舍水电费信息管理系统
    26 行为型模式-命令模式
    常用网络硬件的基本概念
    Spring Data JPA @Entity之间的关联关系注解如何正确使用?
    多线程并发编程
    SpringBoot 注解简介(持续更新)
  • 原文地址:https://blog.csdn.net/xiyafei122/article/details/126294489