在进行项目编写前,我们还需要知道一个东西,就是SpringBoot对我们的SpringMVC还做了哪些配置,包括如何扩展,如何定制,只有把这些都搞清楚了,我们在之后使用才会更加得心应手
@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 {};
}
标注了@AutoConfigurationPackage,并且导入了AutoConfigurationImportSelector
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
@AutoConfigurationPackage注解导入了AutoConfigurationPackages.Registrar。
下面来看看这两个导入类
AutoConfigurationPackages.Registrar
这是一个内部类,外部类AutoConfigurationPackages是一个抽象类
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//注册
register(registry, new PackageImport(metadata).getPackageName());
}
//这个方法没有地方调用,暂不分析
@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也是一个内部类,构造方法中赋值了一个成员变量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方法中会根据@AutoConfigurationPackage标注类的全限定名,获取@AutoConfigurationPackage标注类的包名。
然后将@AutoConfigurationPackage标注类的包名赋值给PackageImport的成员变量packageName。
String getPackageName() {
return this.packageName;
}
getPackageName方法只是简单的将PackageImport#packageName返回。
然后调用外部类AutoConfigurationPackages的静态方法register
private static final String BEAN = AutoConfigurationPackages.class.getName();
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
//已经注册过 BEAN 了,代表不是第一次调用AutoConfigurationPackages.Registrar
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
//将这次调用AutoConfigurationPackages.Registrar,将标注@AutoConfigurationPackage 注解的类的包名添加到 BEAN 的参数中
constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
}
else {
//第一次调用AutoConfigurationPackages.Registrar,注册 BEAN
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
//获取BasePackages构造器的参数,是个 String... ,将packageNames放到数组第一个位置
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。
已经注册过AutoConfigurationPackages
private static String[] addBasePackages(ConstructorArgumentValues constructorArguments, String[] packageNames) {
//取出BasePackages构造器的参数 String...
String[] existing = (String[]) constructorArguments.getIndexedArgumentValue(0, String[].class).getValue();
//创建新的集合,将原有的包名和现有的包名添加进去,用set去重,然后返回
Set<String> merged = new LinkedHashSet<>();
merged.addAll(Arrays.asList(existing));
merged.addAll(Arrays.asList(packageNames));
return StringUtils.toStringArray(merged);
}
AutoConfigurationImportSelector
AutoConfigurationImportSelector实现了DeferredImportSelector,DeferredImportSelector实现了ImportSelector。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//不起用自动装配
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//获得AutoConfiguration的注解元数据
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);
//获取实现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实现类名
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//利用spi获取实现了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);
}
根据AutoConfigurationImportFilter的实现类过滤自动装配类
到此这篇关于SpringBoot快速通关自动配置应用的文章就介绍到这了,更多相关SpringBoot自动配置内容请搜索编程学习网以前的文章希望大家以后多多支持编程学习网!
本文标题为:SpringBoot快速通关自动配置应用
基础教程推荐
- Java数据结构之对象比较详解 2023-03-07
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- Java实现查找文件和替换文件内容 2023-04-06
- Java实现线程插队的示例代码 2022-09-03
- java实现多人聊天系统 2023-05-19
- springboot自定义starter方法及注解实例 2023-03-31
- Java文件管理操作的知识点整理 2023-05-19
- Java并发编程进阶之线程控制篇 2023-03-07
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02
- java基础知识之FileInputStream流的使用 2023-08-11