主程序代码:
/**
* @SpringBootApplication 来表标注一个主程序类,说明这是一个spring boot的应用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) throws Exception {
//启动主程序
SpringApplication.run(HelloWorldMainApplication.class, args);
}
}
我们通过run这个main程序,就可以直接启动整个springboot应用。在这个主程序最核心的就是 @SpringBootApplication注解。
@SpringBootApplication: Spring Boot应用标注在某个类上说明这个类是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}
)}
)
public @interface SpringBootApplication {。。。。。。。}
我们能看到里面的注解有@SpringBootConfiguration、@EnableAutoConfiguration两个核心注解。
我们点击@SpringBootConfiguration查看源码如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
它实质就是spring的一个@Configuration注解( @Configuration:配置类上来标注这个注解 )
配置类就等价于我们应用spring框架时的配置文件;在点击@Configuration,会发现它实质也是一个组件@Component,所以配置类也是容器中的一个组件。
我们注解了配置类,但是类如何导入呢?这就需要用第二个注解@EnableAutoConfiguration(开启自动配置)。
@EnableAutoConfiguration:开启自动配置功能;以前我们需要配置的东西,Spring Boot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;点击查看配置源码:
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
@AutoConfigurationPackage:自动配置包
@Import(AutoConfigurationPackages.Registrar.class):
Spring的底层注解@Import,给容器中导入一个组件;导入的组件由
AutoConfigurationPackages.Registrar.class;它具体导入那些类组件呢?
通过点击 Registrar 查看源码会发现里面有个需要导入的组件的包信息导入类,里面有一个registerBeanDefinitions的一个方法。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
通过debugger的方式可以。我们可以看到metadata的值(也就是导入的包)是什么。
我本地地情况是:也就是@SpringBootApplication注解类所在的包目录下。所以注解@AutoConfigurationPackage的核心功能就是:将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;
@Import({EnableAutoConfigurationImportSelector.class})
EnableAutoConfigurationImportSelector:导入哪些组件的选择器;
将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件。有了自动配置类,免去了我们手动编写配置注入功能组件等的工作;具体源码查看:
通过点击注解
EnableAutoConfigurationImportSelector 进入到
EnableAutoConfigurationImportSelector类。
然后查看他的父类AutoConfigurationImportSelector。
在其父类中有一个selectImports(AnnotationMetadata annotationMetadata)的方法。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
configurations = this.sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return (String[])configurations.toArray(new String[configurations.size()]);
} catch (IOException var6) {
throw new IllegalStateException(var6);
}
}
}
这里可以看到它将所有需要导入的组件以全类名的数组方式返回。
看到这里还是会有一个疑问,那就是它怎么就知道要导入这些配置,或者或这些导入控制中心又在那呢?
我来看到selectImports()这个方法的代码。
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
中有一个getCandidateConfigurations()方法。点进去会看到:
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;
}
这其中会有一个方法
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
点击loadFactoryNames();
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
会看到它通过类加载器去加载一个spring.factories的配置文件。这个文件中就配置了需要配置注入的组件。
spring.factories这个文件我们在导入的spring-boot-autoconfigure.jar的META-INF下找到。
Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;以前我们需要自己配置的东西,自动配置类都帮我们;所以J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-1.5.9.RELEASE.jar;
这就是一个helloworld应用执行的基本流程以及spring-boot通过注解帮我们做了一个web应用应该有哪些配置的过程。下一节,通过IDEA快速创建spring-boot项目之基本目录结构介绍。