SpringBoot快速通關(guān)自動(dòng)配置應(yīng)用
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}標(biāo)注了@AutoConfigurationPackage,并且導(dǎo)入了AutoConfigurationImportSelector
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}@AutoConfigurationPackage注解導(dǎo)入了AutoConfigurationPackages.Registrar。
下面來看看這兩個(gè)導(dǎo)入類
AutoConfigurationPackages.Registrar
這是一個(gè)內(nèi)部類,外部類AutoConfigurationPackages是一個(gè)抽象類
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//注冊
register(registry, new PackageImport(metadata).getPackageName());
}
//這個(gè)方法沒有地方調(diào)用,暫不分析
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}注冊
private final String packageName;
PackageImport(AnnotationMetadata metadata) {
this.packageName = ClassUtils.getPackageName(metadata.getClassName());
}
PackageImport也是一個(gè)內(nèi)部類,構(gòu)造方法中賦值了一個(gè)成員變量packageName。
public static String getPackageName(String fqClassName) {
Assert.notNull(fqClassName, "Class name must not be null");
int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
}getPackageName方法中會(huì)根據(jù)@AutoConfigurationPackage標(biāo)注類的全限定名,獲取@AutoConfigurationPackage標(biāo)注類的包名。
然后將@AutoConfigurationPackage標(biāo)注類的包名賦值給PackageImport的成員變量packageName。
String getPackageName() {
return this.packageName;
}getPackageName方法只是簡單的將PackageImport#packageName返回。
然后調(diào)用外部類AutoConfigurationPackages的靜態(tài)方法register
private static final String BEAN = AutoConfigurationPackages.class.getName();
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
//已經(jīng)注冊過 BEAN 了,代表不是第一次調(diào)用AutoConfigurationPackages.Registrar
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
//將這次調(diào)用AutoConfigurationPackages.Registrar,將標(biāo)注@AutoConfigurationPackage 注解的類的包名添加到 BEAN 的參數(shù)中
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
}
else {
//第一次調(diào)用AutoConfigurationPackages.Registrar,注冊 BEAN
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
//獲取BasePackages構(gòu)造器的參數(shù),是個(gè) String... ,將packageNames放到數(shù)組第一個(gè)位置
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}注冊AutoConfigurationPackages
static final class BasePackages {
private final List<String> packages;
private boolean loggedBasePackageInfo;
BasePackages(String... names) {
List<String> packages = new ArrayList<>();
for (String name : names) {
if (StringUtils.hasText(name)) {
packages.add(name);
}
}
this.packages = packages;
}
List<String> get() {
if (!this.loggedBasePackageInfo) {
if (this.packages.isEmpty()) {
if (logger.isWarnEnabled()) {
...//只是輸出日志
}
}
else {
if (logger.isDebugEnabled()) {
String packageNames = StringUtils.collectionToCommaDelimitedString(this.packages);
...//輸出日志
}
}
this.loggedBasePackageInfo = true;
}
return this.packages;
}
}注冊時(shí)bean的名稱是上面的 BEAN,bean的類為BasePackages。
已經(jīng)注冊過AutoConfigurationPackages
private static String[] addBasePackages(ConstructorArgumentValues constructorArguments, String[] packageNames) {
//取出BasePackages構(gòu)造器的參數(shù) String...
String[] existing = (String[]) constructorArguments.getIndexedArgumentValue(0, String[].class).getValue();
//創(chuàng)建新的集合,將原有的包名和現(xiàn)有的包名添加進(jìn)去,用set去重,然后返回
Set<String> merged = new LinkedHashSet<>();
merged.addAll(Arrays.asList(existing));
merged.addAll(Arrays.asList(packageNames));
return StringUtils.toStringArray(merged);
}
AutoConfigurationImportSelector
AutoConfigurationImportSelector實(shí)現(xiàn)了DeferredImportSelector,DeferredImportSelector實(shí)現(xiàn)了ImportSelector。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//不起用自動(dòng)裝配
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//獲得AutoConfiguration的注解元數(shù)據(jù)
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//獲取注解的屬性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//獲取實(shí)現(xiàn)EnableAutoConfiguration的類名集合
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//去重
configurations = removeDuplicates(configurations);
//獲取要排除的類名
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
//排除
configurations.removeAll(exclusions);
//過濾
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}獲取所有EnableAutoConfiguration實(shí)現(xiàn)類名
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//利用spi獲取實(shí)現(xiàn)了EnableAutoConfiguration的類名集合
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
去重
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
獲取要排除的類名
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
excluded.addAll(asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
private List<String> getExcludeAutoConfigurationsProperty() {
if (getEnvironment() instanceof ConfigurableEnvironment) {
Binder binder = Binder.get(getEnvironment());
return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
.orElse(Collections.emptyList());
}
String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
}過濾
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return new ArrayList<>(result);
}protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
根據(jù)AutoConfigurationImportFilter的實(shí)現(xiàn)類過濾自動(dòng)裝配類
到此這篇關(guān)于SpringBoot快速通關(guān)自動(dòng)配置應(yīng)用的文章就介紹到這了,更多相關(guān)SpringBoot自動(dòng)配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot自動(dòng)配置原理分析
- SpringBoot自動(dòng)配置深入探究實(shí)現(xiàn)原理
- Java SpringBoot自動(dòng)配置原理詳情
- Springboot自動(dòng)配置與@Configuration配置類詳解
- SpringBoot超詳細(xì)講解自動(dòng)配置原理
- SpringBoot自動(dòng)配置實(shí)現(xiàn)的詳細(xì)步驟
- SpringBoot2入門自動(dòng)配置原理及源碼分析
- SpringBoot2零基礎(chǔ)到精通之自動(dòng)配置底層分析及小技巧
- SpringBoot自動(dòng)配置特點(diǎn)與原理詳細(xì)分析
相關(guān)文章
Java中HTTP GET方法調(diào)用帶有body的問題解決
這篇文章主要為大家詳細(xì)介紹了Java如何解決HTTP GET方法調(diào)用帶有body的問題,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2024-02-02
基于springboot服務(wù)間Feign調(diào)用超時(shí)的解決方案
這篇文章主要介紹了基于springboot服務(wù)間Feign調(diào)用超時(shí)的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
SpringBoot整合阿里云視頻點(diǎn)播的過程詳解
視頻點(diǎn)播(ApsaraVideo for VoD)是集音視頻采集、編輯、上傳、自動(dòng)化轉(zhuǎn)碼處理、媒體資源管理、分發(fā)加速于一體的一站式音視頻點(diǎn)播解決方案。這篇文章主要介紹了SpringBoot整合阿里云視頻點(diǎn)播的詳細(xì)過程,需要的朋友可以參考下2021-12-12
SpringBoot項(xiàng)目啟動(dòng)錯(cuò)誤:找不到或無法加載主類的三種解決方法
在開發(fā)SpringBoot應(yīng)用時(shí),經(jīng)常可能會(huì)遇到一個(gè)啟動(dòng)錯(cuò)誤:“錯(cuò)誤:找不到或無法加載主類 com.example.controller.demo.DemoApplication”,本文將介紹三種解決這一問題的方法,需要的朋友可以參考下2024-10-10
springboot使用jasypt對配置文件加密加密數(shù)據(jù)庫連接的操作代碼
這篇文章主要介紹了springboot使用jasypt對配置文件加密加密數(shù)據(jù)庫連接的操作代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01
JAVA中ListIterator和Iterator詳解與辨析(推薦)
這篇文章主要介紹了JAVA中ListIterator和Iterator詳解與辨析,需要的朋友可以參考下2017-04-04
Java中jar包運(yùn)行后顯示:沒有主清單屬性的解決方案
這篇文章主要介紹了Java中jar包運(yùn)行后顯示:沒有主清單屬性的解決方案,文中給大家分析了三個(gè)主要原因,并通過代碼示例和圖文講解的非常詳細(xì),需要的朋友可以參考下2024-04-04
記一次線上SpringCloud Feign請求服務(wù)超時(shí)異常排查問題
這篇文章主要介紹了記一次線上SpringCloud Feign請求服務(wù)超時(shí)異常排查問題,本項(xiàng)目與下游項(xiàng)目均注冊在Eureka上面,對這個(gè)1秒就超時(shí)感到很迷惑,于是開始查閱底層源碼之旅。需要的朋友可以參考下2022-01-01
SpringBoot中實(shí)現(xiàn)啟動(dòng)任務(wù)的實(shí)現(xiàn)步驟
這篇文章主要介紹了SpringBoot中實(shí)現(xiàn)啟動(dòng)任務(wù)的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09

