解決Spring Boot 多模塊注入訪問不到j(luò)ar包中的Bean問題
情景描述
一個(gè)聚合項(xiàng)目spring-security-tutorial,其中包括4個(gè)module,pom如下所示:
<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>
在此項(xiàng)目中,子項(xiàng)目security-browser是一個(gè)簡(jiǎn)單的maven項(xiàng)目,打成jar包,供security-demo使用,security-demo項(xiàng)目是一個(gè)springboot項(xiàng)目。
問題描述
在security-browser項(xiàng)目中自動(dòng)注入了一個(gè)配置類,如下所示:
/**
* @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中使用此配置類時(shí),不起作用。
問題分析
導(dǎo)致此類問題的主要原因是,此類不在Spring Boot的組件掃描范圍之內(nèi)。
1. 關(guān)于 Spring Boot 自動(dòng)注入及組件掃描
在平時(shí)使用 Spring Boot 時(shí),常常會(huì)使用到@Configuration,@Contoller,@Service,@Component等注解,被添加這些注解的類,在 Spring Boot 啟動(dòng)時(shí),會(huì)自動(dòng)被 Spring 容器管理起來。
上面提到了,添加了一些注解的類會(huì)在Spring Boot 容器啟動(dòng)時(shí),被加載到Spring 容器中。那么,組件掃描的作用就是:當(dāng) Spring Boot 啟動(dòng)時(shí),根據(jù)定義的掃描路徑,把符合掃描規(guī)則的類裝配到spring容器中。
2. Spring Boot 中 @ComponentScan
簡(jiǎn)單的介紹了@ComponentScan的基礎(chǔ)作用,這個(gè)注解為我們使用提供了一些可自定義配置屬性,先來看看@ComponentScan注解源碼:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
// 指定掃描包的位置(同:basePackages 屬性),可以是單個(gè)路徑,也可以是掃描的路徑數(shù)組
@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;
// 控制符合組件檢測(cè)條件的類文件 默認(rèn)是包掃描下的 **/*.class
String resourcePattern() default "**/*.class";
// 是否開啟對(duì)@Component,@Repository,@Service,@Controller的類進(jìn)行檢測(cè)
boolean useDefaultFilters() default true;
// 包含的過濾條件
// 1. FilterType.ANNOTATION: 按照注解過濾
// 2. FilterType.ASSIGNABLE_TYPE: 按照給定的類型
// 3. FilterType.ASPECTJ: 使用ASPECTJ表達(dá)式
// 4. FilterType.REGEX: 正則
// 5. FilterType.CUSTOM: 自定義規(guī)則
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 {};
}
}
總結(jié)一下@ComponentScan的常用方式如下:
通過使用value,basePackages屬性來指定掃描范圍;
自定掃描路徑下邊帶有@Controller,@Service,@Repository,@Component注解加入Spring容器
通過includeFilters加入掃描路徑下沒有以上注解的類加入spring容器
通過excludeFilters過濾出不用加入spring容器的類
自定義增加了@Component注解的注解方式
3. Spring Boot 中 @SpringBootApplication
在創(chuàng)建Spring Boot 項(xiàng)目之后,在默認(rèn)的啟動(dòng)類上會(huì)被添加@SpringBootApplication注解,這個(gè)注解默認(rèn)幫我們開啟一些自動(dòng)配置的功能,比如:基于Java的Spring配置,組件掃描,特別是用于啟用Spring Boot的自動(dòng)配置功能。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration // 允許自動(dòng)配置
@ComponentScan(
excludeFilters = {@Filter( // 定義排除規(guī)則
type = FilterType.CUSTOM, // 采用自定義的方式
classes = {TypeExcludeFilter.class} // 自定義實(shí)現(xiàn)邏輯
), @Filter( // 同上
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// 為 @EnableAutoConfiguration 添加 exclude 規(guī)則
@AliasFor(
annotation = EnableAutoConfiguration.class,
attribute = "exclude"
)
Class<?>[] exclude() default {};
// 為 @EnableAutoConfiguration 添加 excludeName 規(guī)則
@AliasFor(
annotation = EnableAutoConfiguration.class,
attribute = "excludeName"
)
String[] excludeName() default {};
// 為 @ComponentScan 添加 basePackages 規(guī)則
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
// 為 @ComponentScan 添加 basePackageClasses 規(guī)則
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackageClasses"
)
Class<?>[] scanBasePackageClasses() default {};
}
從上面的源碼部分可以看到,@SpringBootApplication是一個(gè)組合注解,也就相當(dāng)于使用一個(gè)@SpringBootApplication可以替代@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan幾個(gè)注解聯(lián)合使用。
注:此注釋從SpringBoot 1.2開始提供,這意味著如果你運(yùn)行的是較低的版本,并且如果你需要這些功能,你需要手動(dòng)添加@Configuration,@CompnentScan和@EnableAutoConfiguration。
那么,可能會(huì)有這樣的問題,我只是使用了一個(gè)@SpringBootApplication注解,但是我如何對(duì)@ComponentScan的屬性做自定義配置呢?
當(dāng)然,Spring 團(tuán)隊(duì)已經(jīng)很好的解決了這個(gè)問題,在@SpringBootApplication注解類中的屬性上添加@AliasFor注解,從而實(shí)現(xiàn)通過對(duì)@SpringBootApplication中的屬性進(jìn)行自定義,達(dá)到對(duì)對(duì)應(yīng)的注解的屬性的自定義。
比如:
@AliasFor(
annotation = ComponentScan.class,
attribute = "basePackages"
)
String[] scanBasePackages() default {};
這段代碼就是實(shí)現(xiàn),通過對(duì)@SpringBootApplication的屬性scanBasePackages,實(shí)現(xiàn)對(duì)@ComponentScan中的屬性basePackages進(jìn)行自定義。
4. 回答開篇問題
先看看項(xiàng)目結(jié)構(gòu),項(xiàng)目入口文件在子項(xiàng)目security-demo中,并且入口類所在包位置為:package com.github.jdkong.security。
也就是說,在不做任何配置的情況下,此項(xiàng)目只會(huì)掃描當(dāng)前包路徑及其子路徑下的文件,并將符合條件的對(duì)象注入到容器中管理。
再看看配置文件所在的包路徑位置:package com.github.jdkong.browser.config,可見此包路徑并不在項(xiàng)目掃描的路徑范圍之內(nèi)。
這也就導(dǎo)致了,我們定義的配置類,雖然加了@Configuration也不會(huì)對(duì)我們的項(xiàng)目起到作用。
可以對(duì)項(xiàng)目注解進(jìn)行稍微修改,制定掃描包的范圍,就可以簡(jiǎn)單的解決這個(gè)問題。如下:
@SpringBootApplication(scanBasePackages="com.github.jdkong")
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
5. 補(bǔ)充說明:@AliasFor
在Spring注解中,經(jīng)常會(huì)發(fā)現(xiàn)很多注解的不同屬性起著相同的作用,比如@ComponentScan的value屬性和basePackages屬性。所以在使用的時(shí)候就需要做一些基本的限制,比如value和basePackages的值不能沖突,比如任意設(shè)置value或者設(shè)置basePackages屬性的值,都能夠通過另一個(gè)屬性來獲取值等等。為了統(tǒng)一處理這些情況,Spring創(chuàng)建了@AliasFor標(biāo)簽。
以上這篇解決Spring Boot 多模塊注入訪問不到j(luò)ar包中的Bean問題就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot 整合 freemarker代碼實(shí)例
這篇文章主要介紹了springboot 整合 freemarker代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
最簡(jiǎn)單的Spring Cloud教程第一篇:服務(wù)的注冊(cè)與發(fā)現(xiàn)(Eureka)
這篇文章主要給大家介紹了關(guān)于Spring Cloud服務(wù)的注冊(cè)與發(fā)現(xiàn)(Eureka)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring cloud具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-08-08
JAVA中關(guān)于Long類型返回前端精度丟失問題處理辦法
這篇文章主要介紹了后端JavaBean的id屬性從Long類型改為雪花算法后出現(xiàn)的精度丟失問題,解決方案包括將id字段類型改為字符串或使用Jackson序列化方式,需要的朋友可以參考下2024-11-11
使用maven創(chuàng)建web項(xiàng)目的方法步驟(圖文)
本篇文章主要介紹了使用maven創(chuàng)建web項(xiàng)目的方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01
在啟動(dòng)后臺(tái) jar包時(shí),使用指定的 application.yml操作
這篇文章主要介紹了在啟動(dòng)后臺(tái) jar包時(shí),使用指定的 application.yml操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10
使用Spring Security和JWT實(shí)現(xiàn)安全認(rèn)證機(jī)制
在現(xiàn)代 Web 應(yīng)用中,安全認(rèn)證和授權(quán)是保障數(shù)據(jù)安全和用戶隱私的核心機(jī)制,Spring Security 是 Spring 框架下專為安全設(shè)計(jì)的模塊,具有高度的可配置性和擴(kuò)展性,而 JWT則是當(dāng)前流行的認(rèn)證解決方案,所以本文介紹了如何使用Spring Security和JWT實(shí)現(xiàn)安全認(rèn)證機(jī)制2024-11-11

