- 前言
- 1、构建一个SpringBoot应用
- 2、探究自动装配原理
- 小结
前言
Spring是一个轻量级框架,其目的是简化JavaEE的开发,主要运用到的是IoC和AOP两个手段。
而SpringBoot是简化Spring应用的开发,其最核心的思想就是约定优于配置。所谓的约定优于配置其目的是减少配置的数量来提升开发效率。
那SpringBoot是怎么做的呢?
1、构建一个SpringBoot应用 2、探究自动装配原理
a. 找到其主启动类
@SpringBootApplication
public class SpringBootAutoConfigTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAutoConfigTestApplication.class, args);
}
}
b. 其中@SpringBootApplication表示主启动类,进入此注解,可以看到如下的类
@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 {
// 省略代码
}
c. 在此类中,我们主要关注@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 {};
}
d. 其中@AutoConfigurationPackage表示将此包下的所有组件注册到Spring IoC容器中,我们重点关注@Import({AutoConfigurationImportSelector.class})这个注解,我们点击AutoConfigurationImportSelector这个类进去可以看到实现了ImportSelector重写了selectImports方法
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
// 省略部分代码
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
}
e. 其中this.getAutoConfigurationEntry此方法是获得一个自动配置的实体,我们可以点击进入此方法看有什么
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
f. 其中this.getAttributes()是获得@EnableAutoConfiguration中的属性exclude()和excludeName();
this.getCandidateConfigurations()方法是获得所有自动装配的配置类,是自动装配的核心方法;
this.removeDuplicates()方法是去除重复的配置项;
this.getExclusions()是根据@EnableAutoConfiguration中的属性exclude()把不需要装配的配置类移除
我们来看getCandidateConfigurations()此方法
protected ListgetCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader())); ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct."); return configurations; }
g. 在此方法中我们可以看到SpringFactoriesLoader.loadFactoryNames()此静态方法
public static ListloadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoader == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }
h. 此方法返回一个集合loadSpringFactories,我们点击此方法
private static Map> loadSpringFactories(ClassLoader classLoader) { Map > result = (Map)cache.get(classLoader); if (result != null) { return result; } else { HashMap result = new HashMap(); try { Enumeration urls = classLoader.getResources("META-INF/spring.factories"); while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry, ?> entry = (Entry)var6.next(); String factoryTypeName = ((String)entry.getKey()).trim(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); String[] var10 = factoryImplementationNames; int var11 = factoryImplementationNames.length; for(int var12 = 0; var12 < var11; ++var12) { String factoryImplementationName = var10[var12]; ((List)result.computeIfAbsent(factoryTypeName, (key) -> { return new ArrayList(); })).add(factoryImplementationName.trim()); } } } result.replaceAll((factoryType, implementations) -> { return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); }); cache.put(classLoader, result); return result; } catch (IOException var14) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14); } } }
i. 在此方法中,我们看到了classLoader.getResources(“META-INF/spring.factories”);这个方法,根据Spring的SPI机制,会扫描classpath下的META-INF/spring.factories文件,我们找到spring-boot-autoconfigure.jar
org.springframework.boot.autoconfigure.EnableAutoConfiguration= org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration, org.springframework.boot.autoconfigure.aop.AopAutoConfiguration, org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration, org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration, org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration, ...
j. 可以看到有这些自动配置类,然后再回到getAutoConfigurationEntry方法里通过去重,exclude排除等操作得到最终的自动配置类
小结
简单总结如下:
a. 通过@EnableAutoConfiguration里的@Import({AutoConfigurationImportSelector.class})实现配置类的导入
b. AutoConfigurationImportSelector这个类实现了ImportSelector接口并且重写了selectImports方法来选择性批量配置类
c. 通过SpringFactoriesLoader.loadFactoryNames()此静态方法扫描classpath下的META-INF/spring.factories文件,读取需要实现的自动装配的配置类
d. 通过去重,exclude排除等操作得到最终的自动配置类
以上就是SpringBoot的自动装配原理,有了这些自动装配类,免去了我们手动编写配置文件的工作从而提高开发效率。也为后面SpringCloud出生做了铺垫。



