《精通Spring MVC 4》——1.6 幕后的Spring Boot
本节书摘来自异步社区《精通Spring MVC 4》一书中的第1章,第1.6节,作者:【美】Geoffroy Warin著,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.6 幕后的Spring Boot如果你之前搭建过Spring MVC应用,那么可能已经习惯于编写相关的XML文件或Java注解配置类。
一般来讲,初始的步骤如下所示:
1.初始化Spring MVC的DispatcherServlet;
2.搭建转码过滤器,保证客户端请求进行正确地转码;
3.搭建视图解析器(view resolver),告诉Spring去哪里查找视图,以及它们是使用哪种方言编写的(JSP、Thymeleaf模板等);
4.配置静态资源的位置(CSS、JS);
5.配置所支持的地域以及资源bundle;
6.配置multipart解析器,保证文件上传能够正常工作;
7.将Tomcat或Jetty包含进来,从而能够在Web服务器上运行我们的应用;
8.建立错误页面(如404)。
不过,Spring Boot为我们处理了所有的事情。因为这些配置一般是与应用相关的,所以你可以无限制地将它们进行组合。
在一定程度上来讲,Spring Boot是带有一定倾向性的Spring项目配置器。它基于约定,并且默认会在你的项目中使用这些约定。
1.6.1 分发器和multipart配置
接下来,让我们看一下在幕后到底发生了什么。
我们使用默认生成的Spring Boot配置文件,并将其设置为debug模式。在src/main/resources/ application.properties中添加下面这一行:
debug=true
现在,如果重新启动应用的话,就能看到Spring Boot的自动配置报告。它分为两部分:一部分是匹配上的(positive matches),列出了应用中,所有的自动配置,另一部分是没有匹配上的(negative matches),这部分是应用在启动的时候,需求没有满足的Spring Boot自动配置:
========================= AUTO-CONFIGURATION REPORT =========================
DispatcherServletAutoConfiguration - @ConditionalOnClass classes found: org.Springframework.web. servlet.DispatcherServlet (OnClassCondition) - found web application StandardServletEnvironment (OnWebApplicationCondition)
EmbeddedServletContainerAutoConfiguration - found web application StandardServletEnvironment (OnWebApplicationCondition)
ErrorMvcAutoConfiguration - @ConditionalOnClass classes found: javax.servlet.Servlet,org. springframework.web.servlet.DispatcherServlet (OnClassCondition) - found web application StandardServletEnvironment (OnWebApplicationCondition)
HttpEncodingAutoConfiguration - @ConditionalOnClass classes found: org.springframework.web. filter.CharacterEncodingFilter (OnClassCondition) - matched (OnPropertyCondition)
* {@link EnableAutoConfiguration Auto-configuration} for the Spring * {@link DispatcherServlet}. Should work for a standalone application where an embedded * servlet container is already present and also for a deployable application using * {@link SpringBootServletInitializer}. * @author Phillip Webb * @author Dave Syer @Order(Ordered.HIGHEST_PRECEDENCE) @Configuration @ConditionalOnWebApplication @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class) public class DispatcherServletAutoConfiguration { * The bean name for a DispatcherServlet that will be mapped to the root URL "/" public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet"; * The bean name for a ServletRegistrationBean for the DispatcherServlet "/" public static final String DEFAULT_DISPATCHER_SERVLET_ REGISTRATION_BEAN_NAME = "dispatcherServletRegistration"; @Configuration @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) protected static class DispatcherServletConfiguration { @Autowired private ServerProperties server; @Autowired(required = false) private MultipartConfigElement multipartConfig; @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet() { return new DispatcherServlet(); @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_ NAME) public ServletRegistrationBean dispatcherServletRegistration() ServletRegistrationBean registration = new ServletRegistrationBean( dispatcherServlet(), this.server. getServletMapping()); registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_ NAME); if (this.multipartConfig != null) { registration.setMultipartConfig(this.multipartConfig); return registration; @Bean @ConditionalOnBean(MultipartResolver.class) @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_ RESOLVER_BEAN_NAME) public MultipartResolver multipartResolver(MultipartResolver resolver) { // Detect if the user has created a MultipartResolver but named it incorrectly return resolver; @Order(Ordered.LOWEST_PRECEDENCE - 10) private static class DefaultDispatcherServletCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ConfigurableListableBeanFactory beanFactory = context. getBeanFactory(); ConditionOutcome outcome = checkServlets(beanFactory); if (!outcome.isMatch()) { return outcome; return checkServletRegistrations(beanFactory);
这是一个典型的Spring Boot配置类。
与其他的Spring配置类相同,它使用了@Configuration注解;
一般会通过@Order注解来声明优先等级,可以看到DispatcherServletAutoConfiguration需要优先进行配置;
其中也可以包含一些提示信息,如@AutoConfigureAfter或@AutoConfigureBefore,从而进一步细化配置处理的顺序;
它还支持在特定的条件下启用某项功能。通过使用@ConditionalOnClass (DispatcherServlet.class)这个特殊的配置,能够确保我们的类路径下包含DispatcherServlet,这能够很好地表明Spring MVC位于类路径中,用户当前希望将其启动起来。
这个文件中还包含了Spring MVC分发器Servlet和multipart解析器的典型配置。整个Spring MVC配置被拆分到了多个文件之中。
另外,值得一提的是,这些bean会遵循特定的规则,以此来检查是否处于激活状态。在@Conditional(DefaultDispatcherServletCondition.class)条件满足的情况下,ServletRegistrationBean函数才会启用,这有些复杂,但是能够检查在你的配置中,是否已经注册了分发器Servlet。
只有在满足@ConditionalOnMissingBean(name=DispatcherServlet.MULTIPART_RESOLVER_ BEAN_NAME)条件的情况下,MultipartResolver函数才会处于激活状态,例如,当我们自己还没有注册的时候。
这意味着Spring Boot仅仅是基于常见的使用场景,帮助我们对应用进行配置。不过,可以在任意的地方覆盖这些默认值,并声明自己的配置。
因此,通过查看DispatcherServletAutoConfiguration,就了解了为什么我们已经拥有了分发器Servlet和multipart解析器。
1.6.2 视图解析器、静态资源以及区域配置
另外一个密切相关的配置是WebMvcAutoConfiguration,它声明了视图解析器、地域解析器(localeresolver)以及静态资源的位置。视图解析器如下所示:
@Configuration @Import(EnableWebMvcConfiguration.class) @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter { @Value("${spring.view.prefix:}") private String prefix = ""; @Value("${spring.view.suffix:}") private String suffix = ""; @Bean @ConditionalOnMissingBean(InternalResourceViewResolver.class) public InternalResourceViewResolver defaultViewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix(this.prefix); resolver.setSuffix(this.suffix); return resolver;
视图解析器的配置并没有什么特殊之处,这里真正有意思的是使用了配置属性,从而允许用户对其进行自定义。
它的意思就是说“将会在用户的application.properties文件中查找两个变量,这两个变量的名字是spring.view.prefix和spring.view.suffix”。在配置中只需两行代码就能将视图解析器搭建起来了,这是非常便利的。
为了下一章内容的讲解,你需要牢记这一点,不过,我们现在会继续浏览Spring Boot的代码。
关于静态资源,配置中包含了如下的内容:
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" }; private static final String[] RESOURCE_LOCATIONS; static { RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length + SERVLET_RESOURCE_LOCATIONS.length]; System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, SERVLET_RESOURCE_LOCATIONS.length); System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_ LOCATIONS, SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS. length); @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; Integer cachePeriod = this.resourceProperties.getCachePeriod(); if (!registry.hasMappingForPattern("/webjars/**")) { registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/ webjars/") .setCachePeriod(cachePeriod); if (!registry.hasMappingForPattern("/**")) { registry.addResourceHandler("/**") .addResourceLocations(RESOURCE_LOCATIONS) .setCachePeriod(cachePeriod);
资源位置的声明有点复杂,但是通过它,我们可以了解到以下两点:
对带有“webjar”前缀的资源访问将会在类路径中解析。这样的话,我们就能使用Mavan中央仓库中预先打包好的JavaScript依赖;
我们的静态资源需要放在类路径中,并且要位于以下4个目录中的任意一个之中,“/META-INF/resources/”“/resources/”“/static/”或“/public/”。
WebJars是JAR包格式的客户端JavaScript库,可以通过Maven中央仓库来获取。它们包含了Maven项目文件,这个文件允许定义传递性依赖,能够用于所有基于JVM的应用之中。WebJars是JavaScript包管理器的替代方案,如bower或npm。对于只需要较少JavaScript库的应用来说,这种方案是很棒的。你可以在www.webjars.org站点上看到所有可用的WebJars列表。
在这个文件中,还专门有一部分用来声明地域管理:
@Bean @ConditionalOnMissingBean(LocaleResolver.class) @ConditionalOnProperty(prefix = "spring.mvc", name = "locale") public LocaleResolver localeResolver() { return new FixedLocaleResolver( StringUtils.parseLocaleString(this.mvcProperties.getLocale()));
默认的地域解析器只会处理一个地域,并且允许我们通过spring.mvc.locale配置属性来进行定义。
Spring Boot MVC请求参数通用校验及国际化支持 一、Validation及国际化配置 1、添加依赖 2、校验失败提示消息国际化配置 3、application.properties 4、国际化资源文件 二、代码演示 1、全局异常处理 2、MessageUtils工具类 3、响应VO 2、测试Controller和请求DTO 3、多语言属性文件 4、测试用例 (1)简单对象UserReqDTO测试 (2)包含List集合对象的ChargeRuleReqDTO测试
Spring MVC中文件上传和下载 文件上传需将表格的提交方式设为 POST ,并且将enctype设为 multipart/form-data ,以二进制的方式提交数据。 spring mvc中可通过MultipartResolver监听每个请求,如有上传的文件,则把请求封装为MultipartHttpServletRequest,通过封装的请求可以获取上传的文件信息和上传的文件。 实际使用可直接将MultipartFile作为控制器中请求处理方法的参数,MultipartFile是一个接口,其实现类为CommonsMultipartFile,通过MultipartFile封装的方法也可获取文件相关信息。
java面试题(十八)spring MVC 3.1 什么是MVC? MVC是一种设计模式,在这种模式下软件被分为三层,即Model(模型)、View(视图)、Controller(控制器)。Model代表的是数据,View代表的是用户界面,Controller代表的是数据的处理逻辑,它是Model和View这两层的桥梁。将软件分层的好处是,可以将对象之间的耦合度降低,便于代码的维护。 3.2 DAO层是做什么的? DAO是Data Access Object的缩写,即数据访问对象,在项目中它通常作为独立的一层,专门用于访问数据库。这一层的具体实现技术有很多,常用的有Spring JDBC、Hibernate、JPA、
异步社区 异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库 立即下载
相关文章
- 面试题_Spring高级篇
- Spring配置类为什么要分Full和Lite模式
- spring boot与spring mvc的区别是什么?
- spring boot: spring Aware的目的是为了让Bean获得Spring容器的服务
- 微服务架构实践 - 你只懂docker与spring boot就够了吗?
- [Spring boot] CommandLineRunner and Autowired
- [Spring Boot] Use Component Scan to scan for Bean
- spring boot单元测试之九:用@MybatisTest注解基于mysql+mybatis测试mapper/sql(spring boot 2.4.4)
- spring boot:为service类做参数化单元测试(spring boot 2.4.3)
- spring boot: 用thymeleaf嵌套循环展示多层数据(spring boot 2.3.2)
- MongoDB最简单的入门教程之四:使用Spring Boot操作MongoDB
- 为什么Spring Boot推荐使用logback-spring.xml来替代logback.xml来配置logback日志的问题分析
- Spring 配置多个数据源,并实现动态切换
- InfoQ:用Spring 2.0和AspectJ简化企业应用程序
- 【SpringBoot系列】Spring Boot+Redis 分布式锁:模拟抢单
- 学习Spring Boot:(二十四)多数据源配置与使用
- 学习Spring Boot:(十四)spring-shiro的密码加密
- Spring Boot 项目打包问题集锦: jar依赖多出boot-inf 文件夹问题/多环境动态打包/缺少BOOT-INF目录问题等...
- Spring Security3详细配置
- Spring Mvc和Spring Boot配置Tomcat支持Https
- 001-Spring Cloud Edgware.SR3 升级最新 Finchley.SR1,spring boot 1.5.9.RELEASE 升级2.0.4.RELEASE注意问题点
- Spring Boot CORS支持
- 什么是Spring Boot
- [spring学习]13、声明式事务(@Transaction)
- 【Spring MVC】Spring MVC实现原理(源码阅读)
- 【java】Spring Boot --spring boot项目整合xxl-job