首頁 > 軟體

Java SpringBoot整合shiro-spring-boot-starterqi專案報錯解決

2022-08-12 18:02:38

1、專案啟動時報錯如下

Description:
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.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

2、原因分析

我的自定義ShiroConfig設定類中新增的安全管理器,

程式碼如下:

@Bean
public SecurityManager securityManager(JwtRealm jwtRealm) {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //設定realm
    securityManager.setRealm(jwtRealm);
    return securityManager;
}

 根據異常資訊檢視ShiroWebAutoConfiguration原始碼時發現其中已經定義了securityManager方法,我們在ShiroConfig設定類中再次定義securityManager方法,因返回的類與其不一樣導致出錯,

ShiroWebAutoConfiguration類中定義的securityManager方法程式碼如下:

@Bean
@ConditionalOnMissingBean
@Override
protected SessionsSecurityManager securityManager(List<Realm> realms) {
    return super.securityManager(realms);
}

下面這些為補充知識:我們都知道@ConditionalOnBean作用是根據value屬性按bean的型別或則bean的名稱判斷bean是否在IOC容器中,如果在就返回true,否則返回false。而@ConditionalOnMissingBean的作用與@ConditionalOnBean相反。如果@ConditionalOnBean和@ConditionalOnMissingBean這兩個註解沒有引數,那這兩個註解以何種方式來判斷呢?在Spring Boot官方檔案中找出了答案。

意思是:在@ConditionalOnMissingBean沒有引數的情況下,目標型別預設為方法的返回型別,如果IOC容器中沒有型別為MyService及其子類的Bean,那麼myServiceBean將被建立。

從原始碼中可以看出@ConditionalOnMissingBean沒有引數,那麼如果IOC容器中沒有型別為SessionsSecurityManager及其子類的Bean,那麼該方法則會執行,並且原始碼securityManager方法返回的是SessionsSecurityManager,而自己定義的ShiroConfig中返回的是SecurityManager(因為@Bean註解會指定改bean的型別為該方法的返回型別),所以它會判斷出IOC容器中沒有型別為SessionsSecurityManager及其子類的Bean,原始碼中的方法執行,故IOC容器中有兩個名為securityManager的Bean,因而報錯。所以如果要自定義securityManager方法,返回型別只能是SessionsSecurityManager及其子類,而SessionsSecurityManager的子類是DefaultSecurityManager,DefaultWebSecurityManager又繼承DefaultSecurityManager,

相關類圖如下:

故而正確的程式碼應該是:

@Bean
public SessionsSecurityManager securityManager(JwtRealm jwtRealm) {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //設定realm
    securityManager.setRealm(jwtRealm);
    return securityManager;
}
 
//或者如下,將方法返回型別改為DefaultWebSecurityManager 
/*@Bean
public DefaultWebSecurityManager securityManager(JwtRealm jwtRealm) {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //設定realm
    securityManager.setRealm(jwtRealm);
    return securityManager;
}*/

3、測試@ConditionalOnMissingBean註解

新建下面3個類:

//動物
@Data
public class Animal {
    private String name;
    private Integer age;
}

//狗
@EqualsAndHashCode(callSuper = true)
@Data
public class Dog extends Animal {
    private String type;
}
 
//二哈
@EqualsAndHashCode(callSuper = true)
@Data
public class TwoHa extends Dog {
    private String a;
}

啟動類:

@SpringBootApplication
//掃描下面的介面生成代理實現類
@MapperScan("com.ncwu.**.domain.mapper")
public class ShiroApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShiroApplication.class, args);
    }

    //若IOC容器中沒有Animal型別及其子類Dog型別的bean時,該方法才會執行
    @Bean
    @ConditionalOnMissingBean
    public Animal twoHa(JwtRealm realm) {
        TwoHa twoHa = new TwoHa();
        twoHa.setType("twoHa1");
        twoHa.setAge(10);
        twoHa.setName("twoHa1");
        return twoHa;
    }

    @Bean
    public Dog twoHa() {
        TwoHa twoHa = new TwoHa();
        twoHa.setType("twoHa2");
        twoHa.setAge(20);
        twoHa.setName("twoHa2");
        return twoHa;
    }
}

測試類:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ShiroApplication.class)
public class TestDao {
    @Autowired
    private ApplicationContext appContext;
    @Test
    public void test() throws Exception{
        /*String[] beanNamesForType = appContext.getBeanNamesForType(Animal.class);
        for (String s : beanNamesForType) {
            System.out.println(s);
        }*/
        appContext.getBean(Animal.class);
        //appContext.getBean("dog");
    }
}

測試結果:

到此這篇關於Java SpringBoot整合shiro-spring-boot-starterqi專案報錯解決的文章就介紹到這了,更多相關Java SpringBoot 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com