SPRINGBOOT启动原理(基于2.x版本)
Posted 盖丽男
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPRINGBOOT启动原理(基于2.x版本)相关的知识,希望对你有一定的参考价值。
目录
版本
版本:2.5.5
注解
我们从启动类入手,springboot的启动类上要添加 @SpringBootApplication
注解,我们先看一下这个注解的作用:
@SpringBootApplication
//用于描述类、接口(包括注解类型) 或enum声明
@Target(ElementType.TYPE)
//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
@Retention(RetentionPolicy.RUNTIME)
//表明这个注解应该被 javadoc工具记录
@Documented
//子类将会继承该注解
@Inherited
//相当于@Configuration
@SpringBootConfiguration
//启用 SpringBoot 的自动配置机制
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = @Filter(
type = FilterType.CUSTOM,
classes = TypeExcludeFilter.class
), @Filter(
type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class
)
)
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//使用Import自动导入所有符合自动配置条件的Bean定义并加载到IOC容器
@Import(AutoConfigurationImportSelector.class)
这个注解里面比较引人注意的是这两个注解:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
介绍
三种将类交给spring管理,也就是加入IOC容器的方式:
- @Bean
- @Componet/@Service
- @Import
@Import一般作用于@Configuration定义的类上,它有三种用法
先假设我们有3个类
public class Apple
public class Banana
public class Cherry
都通过这个类注入:
@Configuration
public class Fruits
指定class数组方式
@Configuration
@Import(Apple.class)
public class Fruits
ImportSelector方式(Spring Boot底层采用比较得多的方式)
public class BananaImportSelector implements ImportSelector
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata)
return new String[]"com.test.Banana";
@Configuration
@Import(Apple.class,BananaImportSelector.class)
public class Fruits
ImportBeanDefinitionRegistrar方式
public class CherryDefinitionRegistrar implements ImportBeanDefinitionRegistrar
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(Cherry.class);
//这里还可以给Cherry这个类改个名字,比如Coconut
registry.registerBeanDefinition("Coconut",rootBeanDefinition);
@Configuration
@Import(Apple.class,BananaImportSelector.class,CherryDefinitionRegistrar.class)
public class Fruits
正题
以上,也就是说,在这个地方,要先引入一些类,而且是通过第二种方式来进行的,我们看下这个类:AutoConfigurationImportSelector.class
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata)
//判断EnableAutoConfiguration是否开启,一般默认开启的
if (!isEnabled(annotationMetadata))
return NO_IMPORTS;
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata)
//这里又判断了一遍EnableAutoConfiguration是否开启
if (!isEnabled(annotationMetadata))
return EMPTY_ENTRY;
//这里可以理解为获取到了EnableAutoConfiguration的属性和我们传入的值。
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//这里可以理解为获取到了所有可以自动注入的类名
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//给这些需要自动注入的类名去重,通过list-set-list的方式
configurations = removeDuplicates(configurations);
//把我们设置了排出的整个set返回回来
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
//验证一下要排除自动的类是否合法,不合法的话会直接抛异常
checkExcludedClasses(configurations, exclusions);
//这里就直接把我们想要排除的类从自动启动里都remove了
configurations.removeAll(exclusions);
//TODO:这块另写一篇 获取过滤器,过滤配置类
configurations = getConfigurationClassFilter().filter(configurations);
//TODO:这块另写一篇 获取所有的AutoConfigurationImportListener类型的监听器。然后广播AutoConfigurationImportEvent事件
fireAutoConfigurationImportEvents(configurations, exclusions);
//配置类名字结合和排除集合封装成AutoConfigurationEntry返回
return new AutoConfigurationEntry(configurations, exclusions);
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata)
//拿到了EnableAutoConfiguration类的名字
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
protected final <T> List<T> removeDuplicates(List<T> list)
return new ArrayList<>(new LinkedHashSet<>(list));
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions)
List<String> invalidExcludes = new ArrayList<>(exclusions.size());
for (String exclusion : exclusions)
if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion))
invalidExcludes.add(exclusion);
if (!invalidExcludes.isEmpty())
handleInvalidExcludes(invalidExcludes);
private ConfigurationClassFilter getConfigurationClassFilter()
if (this.configurationClassFilter == null)
//这里其实获取到了AutoConfigurationImportFilter
List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
for (AutoConfigurationImportFilter filter : filters)
invokeAwareMethods(filter);
this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
return this.configurationClassFilter;
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions)
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty())
//这块主要是获取到了AutoConfigurationImportFilter的三个实现类
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners)
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners()
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions)
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty())
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners)
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners()
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
参考
SpringBoot之@EnableAutoConfiguration注解
SpringBootApplication-@Import(AutoConfigurationImportSelector.class)
以上是关于SPRINGBOOT启动原理(基于2.x版本)的主要内容,如果未能解决你的问题,请参考以下文章
SPRINGBOOT启动原理(基于2.x版本)- SpringApplication里有啥