SpringBoot快速通關(guān)自動配置應(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。
下面來看看這兩個導(dǎo)入類
AutoConfigurationPackages.Registrar
這是一個內(nèi)部類,外部類AutoConfigurationPackages是一個抽象類
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//注冊
register(registry, new PackageImport(metadata).getPackageName());
}
//這個方法沒有地方調(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也是一個內(nèi)部類,構(gòu)造方法中賦值了一個成員變量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方法中會根據(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ù),是個 String... ,將packageNames放到數(shù)組第一個位置
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;
}
}注冊時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)有的包名添加進去,用set去重,然后返回
Set<String> merged = new LinkedHashSet<>();
merged.addAll(Arrays.asList(existing));
merged.addAll(Arrays.asList(packageNames));
return StringUtils.toStringArray(merged);
}
AutoConfigurationImportSelector
AutoConfigurationImportSelector實現(xiàn)了DeferredImportSelector,DeferredImportSelector實現(xiàn)了ImportSelector。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//不起用自動裝配
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);
//獲取實現(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實現(xiàn)類名
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//利用spi獲取實現(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的實現(xiàn)類過濾自動裝配類
到此這篇關(guān)于SpringBoot快速通關(guān)自動配置應(yīng)用的文章就介紹到這了,更多相關(guān)SpringBoot自動配置內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用正則表達式實現(xiàn)找出數(shù)字功能示例
這篇文章主要介紹了Java使用正則表達式實現(xiàn)找出數(shù)字功能,結(jié)合實例形式分析了Java針對數(shù)字的匹配查找及非數(shù)字替換操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2017-03-03
Java模擬實現(xiàn)撲克牌洗牌和發(fā)牌的示例代碼
這篇文章主要為大家詳細介紹了如何利用Java模擬實現(xiàn)撲克牌洗牌和發(fā)牌的功能,文中的示例代碼講解詳細,感興趣的小伙伴可以嘗試一下2022-09-09
Java實現(xiàn)讀取TXT和CSV文件內(nèi)容
SpringBoot中JPA實現(xiàn)Sort排序的三種方式小結(jié)

