springboot 框架能够快速高效的构建一个基于 spirng 框架以及 spring 生态 体系的应用解决方案。它是对“约定优于配置”这个理念下的一个最佳实践。因此它是一个服务于框架的框架,服务的范围是简化配置文件。
·约定优于配置的体现
·maven 的目录结构
a) 默认有 resources 文件夹存放配置文件
b) 默认打包方式为 jar
·spring-boot-starter-web 中默认包含 springmvc相关依赖以及内置的tomcat容器,使得构建一个web应用更加简单
·默认提供 application.properties/yml 文件
·默认通过 spring.profiles.active 属性来决定运行环境时读取的配置文件
·EnableAutoConfiguration 默认对于依赖的 starter 进行自动装载
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication
·@SpringBootConfiguration
@Configuration
public @interface SpringBootConfiguration {
}
spring3基于java5的Annotations特性,推出了基于Java代码和Annotation元信息的依赖关系绑定描述的方式,也就是 JavaConfig。任何一个标注了@Configuration 的 Java 类定义都是一个JavaConfig 配置类。而在这个配置类中,任何标注了@Bean 的方法,它的返回值都会作为 Bean 定义注册到Spring 的 IOC 容器,方法名默认成为这个 bean 的 id。
·@ComponentScan
相当于 xml 配置文件中的
·@EnableAutoConfiguration
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class}) // 使用@Import导入 AutoConfigurationImportSelector
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
· @AutoConfigurationPackage
动态注册bean定义,当前主程序类的同级以及子级的包下的class
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set
· @Import({AutoConfigurationImportSelector.class})
AutoConfigurationImportSelector 继承图如下
-> selectImports -> SpringFactoriesLoader.loadFactoryNames() -> loadSpringFactories()
public abstract class SpringFactoriesLoader {
// 这里的第一个参数是 EnableAutoConfiguration.class
public static List loadFactoryNames(Class> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
// 加载配置资源 META-INF/spring.factories
Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
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();
List factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
result.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var9) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
}
}
}
}
最终:从 META-INF/spring.factories 获取以 EnableAutoConfiguration 为key 的配置类的全类名,最终被纳入 spring 容器
综上可知:@Import 注解可以配置三种不同的 class
- 基于普通 bean 或者带有@Configuration 的 bean 进行注入
- 实现 ImportSelector 接口进行动态注入 -> @Import({AutoConfigurationImportSelector.class})
- 实现 ImportBeanDefinitionRegistrar 接口进行动态注入 -> @Import({Registrar.class})
在分析 AutoConfigurationImportSelector 的源码时,会先扫描 spring-autoconfiguration-metadata.properties文件,最后在扫描 spring.factories 对应的类时,会结合前面的元数据进行过滤,原因是很多的@Configuration 其实是依托于其他的框架来加载的, 如果当前的 classpath 环境下没有相关联的依赖,则意味 着这些类没必要进行加载,所以,通过这种条件过滤可以 有效的减少@configuration 类的数量从而降低SpringBoot 的启动时间。
Conditions相关注解 | 描述 |
---|---|
@ConditionalOnBean | 在存在某个 bean 的时候 |
@ConditionalOnMissingBean | 不存在某个 bean 的时候 |
@ConditionalOnClass | 当前 classpath 可以找到某个类型的类时 |
@ConditionalOnMissingClass | 当前 classpath 不可以找到某个类型的类时 |
@ConditionalOnResource | 当前 classpath 是否存在某个资源文件 |
@ConditionalOnProperty | 当前 jvm 是否包含某个系统属性为某个值 |
@ConditionalOnWebApplication | 当前 spring context 是否是web应用程序 |