@SpringBootApplication
这是一个组合注解,也标记了springboot启动类。
@Target(ElementType.TYPE) //注解的作用目标
@Retention(RetentionPolicy.RUNTIME) //注解的保留位置
@Documented //说明该注解将被包含在javadoc中
@Inherited //说明子类可以继承父类中的该注解
@SpringBootConfiguration //同 configuation
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
@SpringBootConfiguration
首先看第一个注解@SpringBootConfiguration如下: 其实就是对Configuration注解进行了一层包装
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@Configuration
@Configuration注解是spring中的注解,标记这是配置类。
@EnableAutoConfiguration
@EnableAutoConfiguration 是一个组合注解,包含了@AutoConfigurationPackage @Import两个注解
@AutoConfigurationPackage //将启动类信息注册到bean注册表中
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};//设置不加载类型
String[] excludeName() default {};//设置不加载名称
}
@AutoConfigurationPackage
@AutoConfigurationPackage注解其中包含了一个@import注解,@import注解的作用是将一个类加载到spring容器中
@Import(AutoConfigurationPackages.Registrar.class)
接下来分析Registrar主要做了什么
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
//注册bean定义
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
看到registerBeanDefinitions方法,有两个入参AnnotationMetadata和BeanDefinitionRegistry。
AnnotationMetadata
是一个记录注解信息的元对象,记录是哪个类以及哪个包
BeanDefinitionRegistry
是bean定义的注册表
register
接下来看register方法,有两个入参数BeanDefinitionRegistry,packageNames 有两个入参数BeanDefinitionRegistry是bean注册表,packageNames是包路径
private static final String BEAN = AutoConfigurationPackages.class.getName();
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
//如果已经注册过AutoConfigurationPackages则进入
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition
.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0,
addBasePackages(constructorArguments, packageNames));
}
else {
//创建GenericBeanDefinition对象
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
//设置为BasePackages
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//注册到注册表中
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
由此可见@Import(AutoConfigurationPackages.Registrar.class)就是将包路径以及启动类信息注册到beanDefinition注册表中。
@Import(AutoConfigurationImportSelector.class)
将AutoConfigurationImportSelector装配到springIoc容器中。接下来看此类具体做了什么,具体看selectImports方法.
- 判断是否包含enableautoconfiguration注解
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//是否包含enableautoconfiguration注解
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
- 使用类加载器加载配置文件 获取加载类的条件
AutoConfigurationMetadata autoConfigurationMetadata =
AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
看一下AutoConfigurationMetadataLoader.loadMetadata方法。此处path的值是META-INF/spring-autoconfigure-metadata.properties
AutoConfigurationMetadataLoader:
protected static final String PATH = "META-INF/"+ "spring-autoconfigure-metadata.properties";
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, PATH);
}
找到路径下的文件,可发现是一堆配置以 类.条件=值的形式存储。也就是加载这个类需要的条件,以及这个条件具体的值是什么。
3. 获取注解配置的exclude以及excludeName配置,也就是需要过滤的类的配置。
AnnotationAttributes attributes = getAttributes(annotationMetadata);
- 获取所有需要加载的配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
进入getCandidateConfigurations方法,主要看SpringFactoriesLoader.loadFactoryNames方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
...
return configurations;
}
两个入参一个是EnableAutoConfiguration注解类一个是类加载器。
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
//先获取所有需要加载的类,getOrDefault通过第一个参数获取到本次需要的类
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
主要看loadSpringFactories方法
//FACTORIES_RESOURCE_LOCATION的值
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//缓存
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//判断类加载器是否为空,通过类加载器加载资源文件
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
找到META-INF/spring.factories文件,就是要加载的各个组件配置
接下来就是解析url并放入map集合中
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
List<String> factoryClassNames = Arrays.asList(
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
result.addAll((String) entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
}
...
}
}
- 删除重复的需要加载的类
configurations = removeDuplicates(configurations);
- 找到不需要配置的类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
- 校验排除类,如果exclusions不是自动配置类则会抛出异常
checkExcludedClasses(configurations, exclusions);
//移除所有排除类
configurations.removeAll(exclusions);
//根据autoConfigurationMetadata条件过滤不需要加载的配置类
configurations = filter(configurations, autoConfigurationMetadata);
- 发送事件通知给spring自动配置监听器
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
private void fireAutoConfigurationImportEvents(List<String> configurations,Set<String> exclusions) {
//加载AutoConfigurationImportListener类对应spring.factories的类的数组
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
//创建事件
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,
configurations, exclusions);
//遍历监听器,发送事件通知
for (AutoConfigurationImportListener listener : listeners) {
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
@ComponentScan
对AutoConfigurationPackage注解获得的包及其子报进行注解扫描 作用等于<context:componet-scan base-package="xxx.xxx.xxx" />