SpringBoot启动配置
第一个HelloWorld
- 导入spring boot相关依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 编写一个主程序,启动SpringBoot应用
@SpringBootApplication
public class HelloWorld01QuickApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorld01QuickApplication.class, args);
}
}
- 编写一个Controller
@Controller
public class HelloWorldController {
@ResponseBody
@RequestMapping("/hello")
public String hello(){
return "Hello World!";
}
}
- 运行主程序Main方法测试
- 访问http://localhost:8080/hello
简介原理(HelloWorld探究)
再pom.xml文件中,我们可以看到HelloWorld引用了一个上层pom文件,他的上层文件spring-boot-starter-parent
又引用了一个上层文件spring-boot-dependencies
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X9X3h4ut-1588239225049)(C:\Users\lym\AppData\Roaming\Typora\typora-user-images\image-20200430161406719.png)]
spring-boot-dependencies`就是来管理SpringBoot应用里面所有依赖版本,是SpringBoot的版本管理中心,所以我们导出的包的版本不需要我们自己管理。
启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-start-web:
spring-boot-starter: spring-boot场景启动器;帮我们导入了web模块正常运行所依赖的组件;
SpringBoot将所有的功能场景都抽取出来,做成一个个的starters(启动器),只需要再项目里面引入这些starter相关的创景的所有依赖都会导入进来。要用什么功能就导入什么场景的启动器。
主程序类,主入口类
@SpringBootApplication
public class HelloWorld01QuickApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorld01QuickApplication.class, args);
}
}
@SpringBootApplication:
SpringBoot应用标注再某某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
下面是@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}
)}
)
@SpringBootConfiguration
这个注解表示SpringBoot的配置类,标注再某个类上,表示这是一个SpringBoot的配置类。在@SpringBootConfiguration
中我们可以看到@Configuration
注解,表示这是一个配置类。@EnableAutoConfiguration
:开启自动配置功能;
以前我们需要自己配置的东西,SpringBoot会帮我们自动配置,该注解告诉SpringBoot开启自动配置功能。
@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
:
@Import({AutoConfigurationImportSelector.class})
在AutoConfigurationImportSelector
类中有selectImports
方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> 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();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
classLoader.getResources(“META-INF/spring.factories”)由这行代码可知,最终是通过ClassLoader
加载
META-INF/spring.factories
文件中的类来确定自己加载的配置类,该文件中表明了需要导入组件的全类名,通过@Import
这些组件,这些组件就会被添加到容器中,会给容器中导入非常多的自动配置类。