主程序类
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
SpringBoot通过SpringBootApplication这个注解来标注一个主程序类,说明这是一个SpringBoot应用,这也是应用的入口,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用。这也是一个组合注解,我们可以点进去看看。
@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
可以看到它是由多个注解组成,前面几个都是java的元注解,下面介绍几个比较核心的注解
@SpringBootConfiguration
SpringBoot的配置类,标注在某个类上,表示这是一个SpringBoot的配置类;点进去可以看到Spring底层定义的注解@Configuration,一般在配置类上标注这个注解,所谓的配置类就相当于配置文件,每一个配置项都相当于配置类的属性,配置的值等同于属性的值,标注了@Configuration的类才能被Spring以配置类的方式识别。@SpringBootConfiguration效果和@Configuration其实是一样的,只不过它是属于SpringBoot定义的注解罢了。
@EnableAutoConfiguration
从字面理解,就是开启自动配置,以前我们需要配置的东西,SpringBoot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;
@EnableAutoConfiguration注解下面又包含两个核心注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
- @AutoConfigurationPackage
- @Import({AutoConfigurationImportSelector.class})
@AutoConfigurationPackage
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage
AutoConfigurationPackage下面又包含几个注解,比较重要的是@Import({Registrar.class}),这个注解作用是将Registrar这个类导入到ioc容器中,查看其源码
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));
}
}
其中registerBeanDefinitions这个方法即是向容器中导入各种组件,怎么导的主要关注这个参数
(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()),从注解元信息中获取包名,我们可以在这里打个断点,以debug方式运行主程序。
我们在计算下new AutoConfigurationPackages.PackageImport(metadata).getPackageName()这个表达式的值
可以看到包名就是主配置类所在的包名,因此可以得出
@AutoConfigurationPackage的作用就是将主配置类(@SpringBootApplication标注的类)所在包及下面所有子包里面的所有组件扫描到Spring容器
所以说我们一定要把有使用注解的类放在主配置类同包或者主配置类所在包子包下,不然是扫描不到的。
@Import({AutoConfigurationImportSelector.class})
这个注解向容器中导入组件,导入的组件由AutoConfigurationImportSelector(开启自动配置导入选择器)指定,相关导入方法:
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);
}
}
configurations 就包含了所有需要导入的组件的全类名,这些组件就会被添加到容器中,我们可以打个断点看一下
这个方法会给容器中导入非常多的自动配置类(xxxAutoConfiguration),也就是给容器中导入这个场景需要的所有组件,并配置好这些组件;所有有了这些配置类,我们就不需要再手动编写配置文件了。
那么,这些配置类从哪儿得到的呢
通过调用这个静态类,从META-INF/spring.factories这个文件中获取配置
总结来说,Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;
同时,J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-1.5.9.RELEASE.jar中
至此,我们对SpringBoot的核心注解及自动配置原理有了初步的认识,其中涉及到的更多的细节还得我们通过源码来进行更深入的研究。