这里注释的是 springboot2.3.0 的源码
SpringBoot运行机制
主要是依靠几个注解
@SpringBootApplication 下有3个重点注解
@SpringBootConfiguration 相当于spring中的 Configuration,用来标注类为配置类
@ComponentScan:将指定包下需要装配的组件注册到容器中
@EnableAutoConfiguration:进入之后包含两个重要注解
@AutoConfigurationPackage:将主配置类所在的包,作为自动配置的包进行管理
@Import:导入类到ioc容器中
其实就是spring 装配所属依赖的类,再用动态代理的方式注入到Spring容器中
run方法
@SpringBootApplication
@EnableJms
public class SampleActiveMQApplication {
@Bean
public Queue queue() {
return new ActiveMQQueue("sample.queue");
}
public static void main(String[] args) {
SpringApplication.run(SampleActiveMQApplication.class, args);
}
}
点开 @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 {
.......
}点开 @SpringBootApplication 查看 AutoConfigurationImportSelector.class
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
selectImport 方法
/*
*这个方法的返回值包含所有需要注入到容器中的类名
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//非空判断
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}getAutoConfigurationEntry 方法
/**
* 获取打破所有自动配置类,从包的路径中查询所有 META-INF/spring.factories的配置文件 读取里面的内容
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 这个方法下调用 spring.factories 进行读取
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//这个方法 new 了一个 LinkedHashSet 用来做数据的去重
configurations = removeDuplicates(configurations);
//删除需要排除的类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}getCandidateConfigurations 方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//这个方法中读取并解析了spring.factory
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 这里为了提升扫描效率,会先扫描一次缓存
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// FACTORIES_RESOURCE_LOCATION 就是 META-INF/spring.factories 需要扫描的配置文件
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
//扫描 spring.factories 的过程
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
//扫描出来的内容添加到缓存中
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}总结:简单描述了几个重要注解的作用,以及扫描 spring.factory 的过程 ,扫描之后为了读取效率会将结果添加到 cache 缓存中