情景描述
一個聚合項目spring-security-tutorial,其中包括4個module,pom如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
< project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion >4.0.0</ modelVersion > < groupId >com.github.jdkong.security</ groupId > < artifactId >spring-security-tutorial</ artifactId > < version >1.0-SNAPSHOT</ version > < packaging >pom</ packaging > < modules >`` < module >security-core</ module > < module >security-app</ module > < module >security-browser</ module > < module >security-demo</ module > </ modules > <!-- 其他部分省略--> </ project > |
在此項目中,子項目security-browser是一個簡單的maven項目,打成jar包,供security-demo使用,security-demo項目是一個springboot項目。
問題描述
在security-browser項目中自動注入了一個配置類,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/** * @author jdkong */ @Slf4j @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .and() .authorizeRequests() .anyRequest() .authenticated(); } } |
在security-demo中使用此配置類時,不起作用。
問題分析
導致此類問題的主要原因是,此類不在Spring Boot的組件掃描范圍之內。
1. 關于 Spring Boot 自動注入及組件掃描
在平時使用 Spring Boot 時,常常會使用到@Configuration,@Contoller,@Service,@Component等注解,被添加這些注解的類,在 Spring Boot 啟動時,會自動被 Spring 容器管理起來。
上面提到了,添加了一些注解的類會在Spring Boot 容器啟動時,被加載到Spring 容器中。那么,組件掃描的作用就是:當 Spring Boot 啟動時,根據定義的掃描路徑,把符合掃描規則的類裝配到spring容器中。
2. Spring Boot 中 @ComponentScan
簡單的介紹了@ComponentScan的基礎作用,這個注解為我們使用提供了一些可自定義配置屬性,先來看看@ComponentScan注解源碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
@Retention (RetentionPolicy.RUNTIME) @Target ({ElementType.TYPE}) @Documented @Repeatable (ComponentScans. class ) public @interface ComponentScan { // 指定掃描包的位置(同:basePackages 屬性),可以是單個路徑,也可以是掃描的路徑數組 @AliasFor ( "basePackages" ) String[] value() default {}; // 指定掃描包的位置(同:value 屬性) @AliasFor ( "value" ) String[] basePackages() default {}; // 指定具體的掃描的類 Class<?>[] basePackageClasses() default {}; // bean的名稱的生成器 Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator. class ; Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver. class ; ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; // 控制符合組件檢測條件的類文件 默認是包掃描下的 **/*.class String resourcePattern() default "**/*.class" ; // 是否開啟對@Component,@Repository,@Service,@Controller的類進行檢測 boolean useDefaultFilters() default true ; // 包含的過濾條件 // 1. FilterType.ANNOTATION: 按照注解過濾 // 2. FilterType.ASSIGNABLE_TYPE: 按照給定的類型 // 3. FilterType.ASPECTJ: 使用ASPECTJ表達式 // 4. FilterType.REGEX: 正則 // 5. FilterType.CUSTOM: 自定義規則 ComponentScan.Filter[] includeFilters() default {}; // 排除的過濾條件,用法和includeFilters一樣 ComponentScan.Filter[] excludeFilters() default {}; boolean lazyInit() default false ; @Retention (RetentionPolicy.RUNTIME) @Target ({}) public @interface Filter { FilterType type() default FilterType.ANNOTATION; @AliasFor ( "classes" ) Class<?>[] value() default {}; @AliasFor ( "value" ) Class<?>[] classes() default {}; String[] pattern() default {}; } } |
總結一下@ComponentScan的常用方式如下:
通過使用value,basePackages屬性來指定掃描范圍;
自定掃描路徑下邊帶有@Controller,@Service,@Repository,@Component注解加入Spring容器
通過includeFilters加入掃描路徑下沒有以上注解的類加入spring容器
通過excludeFilters過濾出不用加入spring容器的類
自定義增加了@Component注解的注解方式
3. Spring Boot 中 @SpringBootApplication
在創建Spring Boot 項目之后,在默認的啟動類上會被添加@SpringBootApplication注解,這個注解默認幫我們開啟一些自動配置的功能,比如:基于Java的Spring配置,組件掃描,特別是用于啟用Spring Boot的自動配置功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
@Target ({ElementType.TYPE}) @Retention (RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration // 允許自動配置 @ComponentScan ( excludeFilters = { @Filter ( // 定義排除規則 type = FilterType.CUSTOM, // 采用自定義的方式 classes = {TypeExcludeFilter. class } // 自定義實現邏輯 ), @Filter ( // 同上 type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter. class } )} ) public @interface SpringBootApplication { // 為 @EnableAutoConfiguration 添加 exclude 規則 @AliasFor ( annotation = EnableAutoConfiguration. class , attribute = "exclude" ) Class<?>[] exclude() default {}; // 為 @EnableAutoConfiguration 添加 excludeName 規則 @AliasFor ( annotation = EnableAutoConfiguration. class , attribute = "excludeName" ) String[] excludeName() default {}; // 為 @ComponentScan 添加 basePackages 規則 @AliasFor ( annotation = ComponentScan. class , attribute = "basePackages" ) String[] scanBasePackages() default {}; // 為 @ComponentScan 添加 basePackageClasses 規則 @AliasFor ( annotation = ComponentScan. class , attribute = "basePackageClasses" ) Class<?>[] scanBasePackageClasses() default {}; } |
從上面的源碼部分可以看到,@SpringBootApplication是一個組合注解,也就相當于使用一個@SpringBootApplication可以替代@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan幾個注解聯合使用。
注:此注釋從SpringBoot 1.2開始提供,這意味著如果你運行的是較低的版本,并且如果你需要這些功能,你需要手動添加@Configuration,@CompnentScan和@EnableAutoConfiguration。
那么,可能會有這樣的問題,我只是使用了一個@SpringBootApplication注解,但是我如何對@ComponentScan的屬性做自定義配置呢?
當然,Spring 團隊已經很好的解決了這個問題,在@SpringBootApplication注解類中的屬性上添加@AliasFor注解,從而實現通過對@SpringBootApplication中的屬性進行自定義,達到對對應的注解的屬性的自定義。
比如:
1
2
3
4
5
|
@AliasFor ( annotation = ComponentScan. class , attribute = "basePackages" ) String[] scanBasePackages() default {}; |
這段代碼就是實現,通過對@SpringBootApplication的屬性scanBasePackages,實現對@ComponentScan中的屬性basePackages進行自定義。
4. 回答開篇問題
先看看項目結構,項目入口文件在子項目security-demo中,并且入口類所在包位置為:package com.github.jdkong.security。
也就是說,在不做任何配置的情況下,此項目只會掃描當前包路徑及其子路徑下的文件,并將符合條件的對象注入到容器中管理。
再看看配置文件所在的包路徑位置:package com.github.jdkong.browser.config,可見此包路徑并不在項目掃描的路徑范圍之內。
這也就導致了,我們定義的配置類,雖然加了@Configuration也不會對我們的項目起到作用。
可以對項目注解進行稍微修改,制定掃描包的范圍,就可以簡單的解決這個問題。如下:
1
2
3
4
5
6
7
|
@SpringBootApplication (scanBasePackages= "com.github.jdkong" ) public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication. class ,args); } } |
5. 補充說明:@AliasFor
在Spring注解中,經常會發現很多注解的不同屬性起著相同的作用,比如@ComponentScan的value屬性和basePackages屬性。所以在使用的時候就需要做一些基本的限制,比如value和basePackages的值不能沖突,比如任意設置value或者設置basePackages屬性的值,都能夠通過另一個屬性來獲取值等等。為了統一處理這些情況,Spring創建了@AliasFor標簽。
以上這篇解決Spring Boot 多模塊注入訪問不到jar包中的Bean問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/weixin_41540822/article/details/88852973