SpringBoot源码分析
@SpringBootApplication注解由以下3个注解组合
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
- @SpringBootConfiguration里面有@Configuration代表当前是一个配置类
- @ComponentScan指定扫描哪些包
- @EnableAutoConfiguration是下面两个注解的合成
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
@AutoConfigurationPackage利用Registrar给容器中导入一系列组件
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
将指定包下的所有组件导入进来 MainApplication所在的包
@Import(AutoConfigurationImportSelector.class)
1.利用getAutoConfigurationEntry(annotationMetadata);给容器中导入组件
2.List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取到所有需要导入容器中配置类
3.利用工厂加载
Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader)
4 从META-INF/spring.factories位置来加载一个文件
默认扫描我们当前系统里面所有META-INF/spring.factories位置下的文件
springboot默认会在底层配好所有的组件,但如果用户自己配置了则以用户的优先
总结
- springboot先加载所有的自动配置类 xxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件里面的值。xxxProperties里面拿,xxxProperties和配置文件进行了绑定
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 只要用户有自己配置的,就以用户的优先。(订制)
(1)用户直接自己@Bean替换底层的组件
(2)改配置文件中的值(常用),查文档或者底层
xxxAutoConfiguration==> 组件==> xxxProperties里面拿值 ==>application.properties
静态资源配置原理
- springboot启动默认加载xxxAutoConfiguration类(自动配置类)
- springMVC功能的自动配置类WebMvcAutoConfiguration,生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {}
- 给容器中配置了什么
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {}
- 配置文件的相关属性和WebMvcProperties ==spring.mvc、ResourceProperties ==spring.resources进行了绑定
- 如果一个类只有一个有参构造器,有参构造器所有参数的值都会从容器中确定
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
}
- 资源处理的默认规则
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(),
this.resourceProperties.getStaticLocations());
}
禁用所有静态资源
spring:
resources:
add-mappings: false
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
- /META-INF/resources/webjars/目录下的所有文件都能访问到 而且会缓存
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/].
*/
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
静态资源的4个默认的位置
- 欢迎页的处理规则
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
HandlerMapping 处理器映射,保存每一个Handler能处理哪些请求
SpringApplication启动类
run方法里面有new对象
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;//资源加载器 为空
Assert.notNull(primarySources, "PrimarySources must not be null");// 断言
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 启动类是它,以后很多地方用的到
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//web应用程序类型,一般3种,默认是WebApplicationType.SERVLET
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
请求映射
handlerMappings 处理器映射,有6个
springboot自动配置欢迎页的handlerMapping,默认是index.html
请求进来挨个尝试所有的handlerMapping看是否有请求信息
如果有就找到这个请求对应的handler,如果没有,继续在下一个handlerMapping中找
springboot 启动过程
创建springapplication:
- 保存一些信息
- 判断当前应用类型。用ClassUtils 一般是servlet(有可能是return WebApplicationType.REACTIVE;)
- Bootstrappers:初始化启动引导器(List<Bootstrapper):去springfactories文件中找
- 找ApplicationContextInitializer,去springfactories文件中找ApplicationContextInitializer,返回ListInitializers
- 找ApplicationListener:应用监听器
运行springapplication
-
StopWatch
-
记录应用启动时间
-
创建引导上下文(Context环境) createBootstrapContext:
获取所有之前的Bootstrappers,挨个执行initialize()方法来完成对引导启动器上下文环境配置 -
让当前应用进入headless模式 java.awt.headless
-
获取所有的运行时监听器 getRunListeners()【为了方便所有Listener进行时间感知】
getSpringFactoriesInstances 去springfactories文件中找SpringApplicationRunListener
遍历SpringApplicationRunListener调用starting方法
通知所有感兴趣系统正在启动过程的人 ,项目正在starting