如何使用
- 创建springboot应用,选择我们需要的模块;
- springboot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来。
- 编写业务代码。
掌握自动配置原理
springboot的每个场景启动器帮我们配置了什么?能不能修改?能修改什么?xxxxxx
xxxAutoConfiguration:帮我们给容器自动配置组件
xxxProperties:配置类来分组配置文件的内容
静态资源映射
参考org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration代码。
springMVC自动配置原理
参考官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-spring-application
springboot自动配置好了的SpringMVC。
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
- 以下是Springboot对SpringMVC的默认配置:WebMvcAutoConfiguration
The auto-configuration adds the following features on top of Spring’s defaults:
Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
- 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象view,视图对象决定如何渲染(转发?重定向?))
- ContentNegotiatingViewResolver:组合所有的视图解析器;
- 如何定制:我们可以给容器中添加一个视图解析器,自动的将其组合进来。
Support for serving static resources, including support for WebJars (covered later in this document)).
Automatic registration of Converter, GenericConverter, and Formatter beans.
- 自己添加的格式器转换器,我们只需要放到容器中即可。
Support for HttpMessageConverters (covered later in this document).
- HttpMessageConverter:SpringMVC用来转换Http请求和相应的(User<->json);
- HttpMessageConverter:是从容器中获取所有的HttpMessageConverter;
自己给容器中添加HttpMessageConverter只需要将自己的组件注册容器中(通过@Bean,@Component等)
Automatic registration of MessageCodesResolver (covered later in this document).
- 定义错误码生成规则
Static index.html support.
- 支持访问首页
Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
- 我们可以配置一个ConfigurableWebBingdingInitializer来替换默认的(添加到容器中即可)
- 作用是把请求数据绑定到javabean中,会用到上面的消息转换器等功能。
==org.springframework.boot.autoconfigure.web:web的所有自动配置场景都在这个包下面==
If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.
If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.
如何修改SpringBoot的默认配置
模式
- springboot在自动配置很多组件的时候,首先看容器中是否存在用户自定义的(@Bean,@Component),如果有就用用户配置,如果没有,才自动配置;
如果有些组件可以有多个(比如ViewResolver)将用户配置的和自己默认的组合起来; - 扩展SpringMVC
If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.
If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.
- 全面接管SpringMVC
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc
为什么添加@EnableWebMvc,所有的springMVC自动配置失效:
- @EnableWebMvc将WebMvcConfigurationSupport组件导入进来;
- 导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;
嵌入式Servlet启动原理
步骤:
- Springboot根据到的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory。
- EmbeddedServletContainerFactory要创建容器对象就会调用后置处理器:EmbeddedServletContainerCustomizerBeanPostProcessor;
只要是嵌入式的Servlet容器工厂,后置处理器就会工作。 - 后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法;
原理
- 获取嵌入式Servlet容器工厂
- Springboot应用启动run方法;
- refreshContext(context);Springboot刷新IOC容器【创建IOC容器对象,并初始化容器,创建容器中的每一个组件】;如果是web应用创建AnnotationConfigServletWebServerApplicationContext容器。
- refresh(context):刷新刚创建好的IOC容器
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
- onRefresh():web的IOC容器重写了onRefresh方法
protected void onRefresh() {
super.onRefresh();
try {
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
- web IOC容器会创建Servlet容器:createWebServer();
- 获取Servlet容器工厂:
ServletWebServerFactory factory = this.getWebServerFactory();
从IOC容器中获取ServletWebServerFactory ,容器工厂就会创建容器对象,接着就按照步骤里面的1,2,3执行(调用后置处理器,进行自动化配置)。
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
customizer.customize(webServerFactory);
});
}
- 使用容器工厂获取servlet容器
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#selfInitialize - 嵌入式的Servlet容器创建对象并启动Servlet容器。
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
ServletWebServerFactory factory = this.getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
createWebServer.end();
this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var5) {
throw new ApplicationContextException("Cannot initialize servlet context", var5);
}
}
this.initPropertySources();
}
先启动servlet容器,再将ioc容器中剩下没有创建出的对象创建完成。
总之:IOC容器启动时创建servlet容器,servlet容器启动后,ioc容器还会完成一些扫尾工作
使用外置的Servlet容器
嵌入式Servlet容器:
- 优点:简单,便携;
- 缺点:默认不支持JSP,优化定制比较复杂(修改定制器【ServerProperties、自定义定制器】,自己编写嵌入Servlet容器的创建工程)
外置servlet容器
外置servlet容器需要打成war包。
外置servlet启动原理
- jar包:执行Springboot主类的main方法,启动IOC容器的时候创建servlet容器;
- war包:启动servlet容器,servlet启动springboot应用(依靠SpringBootServletInitializer类),然后启动IOC容器;
流程
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
SpringApplicationBuilder builder = this.createSpringApplicationBuilder();
builder.main(this.getClass());
ApplicationContext parent = this.getExistingRootWebApplicationContext(servletContext);
if (parent != null) {
this.logger.info("Root context already created (using as parent).");
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)null);
builder.initializers(new ApplicationContextInitializer[]{new ParentContextApplicationContextInitializer(parent)});
}
builder.initializers(new ApplicationContextInitializer[]{new ServletContextApplicationContextInitializer(servletContext)});
builder.contextFactory((webApplicationType) -> {
return new AnnotationConfigServletWebServerApplicationContext();
});
// configure方法是我们重写的方法,调用了springboot的主类。
builder = this.configure(builder);
builder.listeners(new ApplicationListener[]{new SpringBootServletInitializer.WebEnvironmentPropertySourceInitializer(servletContext)});
SpringApplication application = builder.build();
if (application.getAllSources().isEmpty() && MergedAnnotations.from(this.getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) {
application.addPrimarySources(Collections.singleton(this.getClass()));
}
Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation");
if (this.registerErrorPageFilter) {
application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
}
application.setRegisterShutdownHook(false);
return this.run(application);
}
- springboot应用启动,并创建IOC容器。
参考
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100353.html