主程序
- @SpringBootApplication来标注一个springboot主程序类
- @Configuration:标记配置类,也是一个容器(@Component)
- @EnableAutoConfiguration:开启自动配置功能
- @AutoConfigurationPackage:自动配置包
- @Import,spring底层组件,给容器中导入一个组件
- Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将
这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;以前我们需要自己配置的东
西,自动配置类都帮我们;J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-1.5.9.RELEASE.jar;
yml语法
- 基本语法k: v --> 表示一对键值对
name: jiyu
- 对象/map
- 换行写法
person:
name: jiyu
age: 22
- 行内写法
person: {name: jiyu, age: 22}
- 数组(List, Set)
- 换行写法
animal:
- dog
- pig
- flog
- 行内写法
animal: [dog, pig, flog]
@Value和@ConfigurationProperties的区别
| @ConfigurationProperties | @Value |
配置方式 | 批量指定 | 单个指定属性 |
松散绑定 | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
- @value用于简单获取配置文件,@ConfigurationProperties用于复杂配置
- 松散绑定
- JSR303校验: @Validated @NotNull
- 复杂类型封装: map, list, set等
@PropertySource和@ImportResource和@Bean
- @PropertySource读取指定的配置文件(不能读取yml文件,如需要须配置)
- @ImportResource导入spring的xml配置文件
- @Bean将方法的返回值添加到容器中,在容器的id默认是方法名,配合@Configuration使用
配置文件占位符
- 随机数: ${random.int},${random.int(10)},${random.int[1,2,33,444]}
- 冒号指定默认值:${server.port:8080}
多profile文件
- 主配置文件写成application-{profile}.yml/properties,默认使用application.properties配置文件
- 使用spring.profiles.active=profile激活
- yml使用---作为文档块,文档块可指定profile,可在第一个文档块中指定profile
- 可使用--spring.profiles.active=profile命令行指定
- 可使用-Dspring.profiles.active=profile虚拟机参数指定
配置文件路径的优先级
- 优先级从高到底
- file:./config/application.properties
- file:./application.properties
- classpath:/config/application.properties
- classpath:/application.properties
- 这四个文件位置会形成互补配置
- 命令行参数使用--spring.config.location=filePath指定配置文件
外部配置文件加载顺序
- 优先级从高到低
- 命令行
- 来自Java:comp/env的JNDI属性
- Java系统属性(System.getProperties())
- 操作系统环境变量
- RandomValuePropertySource配置的random.*属性值
- jar包外部application-profile.yml/properties,带profile
- jar包内部application-profile.yml/properties,带profile
- jar包外部application.yml/properties,不带profile
- jar包内部application.yml/properties,不带profile
- 通过@Configuration注解类上的@PropertySource指定
- 通过SpringApplication.setDefaultProperties()指定默认属性
自动配置原理
- springboot启动的时候开启了自动配置功能@EnableAutoConfiguration
- @EnableAutoConfiguration的作用
- 使用AutoConfigurationImportSelector给容器中导入了一些组件
- 导入的组件由selectImports()方法决定
- List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);获取候选配置
- loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader);扫描META-INF/spring.factories文件,并封装成properties对象
- 从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后将其加入到容器中
- META-INF/spring.factories中的内容
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
- 每一个xxxAutoConfiguration都是容器中的一个组件,都加入到容器中用来做自动配置
- 以HttpEncodingAutoConfiguration为例解读自动配置
@Configuration//配置类
//启动指定类的ConfigurationProperties功能,映射HttpEncodingProperties和配置文件并加入ioc容器中
@EnableConfigurationProperties(HttpEncodingProperties.class)
//@Conditional满足条件才会生效,是否web应用
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//是否有CharacterEncodingFilter类
@ConditionalOnClass(CharacterEncodingFilter.class)
//配置文件中是否有spring.http.encoding为enabled的配置,matchIfMissing 如果判断不存在也是成立的
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
//此配置已和配置文件映射
private final HttpEncodingProperties properties;
//只有一个有参构造器,参数的值会从容器中获取
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
//给容器中添加组件,这个组件的某些值需要从properties中获取
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
}
//从配置文件中获取指定的值和bean的属性绑定
@ConfigurationProperties(prefix = "spring.http.encoding")
public class HttpEncodingProperties {
}
- 配置文件能配置的东西参照对应功能的xxxProperties类
- 精髓
- springboot启动时会加载大量配置类
- 如果我们需要的功能springboot已经写好配置类,则默认,如果没有则自定义
- 再看自动配置类中定义了哪些组件,如果有我们需要的则不需要配置,如果没有则自定义配置
- springboot给容器加组件时,会从properties中读取某些,如果有需要自定义的属性,则从配置文件中自定义
@Conditional
@Conditional扩展注解 | 作用(判断是否满足当前指定条件) |
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissingBean | 容器中不存在指定Bean |
@ConditionalOnExpression | 满足SpEL表达式指定 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
配置文件debug=true启动时可打印自动配置报告
面向接口编程
- 代码里使用接口里定义的方法
- 接口里定义的方法通过具体类实现(可插拔)
日志框架
- 日志门面(接口)
- slf4j(simple logging facade for Java): 流行
- jcl(jakarta commons logging): 停止更新
- jboss-jboss-loggin: 使用少
- 日志实现
- logback: log4j的升级版
- log4j: slf4j的实现,性能不太好
- log4j2: apache的,使用少
- jul(Java utils logging): Java原生日志
- slf4j的使用
- 兼容log4j,导入log4j-to-slf4j包
- 兼容其它日志,排除其它框架里的日志框架,增加替代的jar包
springboot对静态资源的映射规则
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = "";
private static final String[] SERVLET_LOCATIONS = { "/" };
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
}
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
//设置映射规则,缓存时间等
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
}
- /webjars/**会到classpath:/META-INF/resources/webjars/寻找资源
- /**没有匹配的情况会到一下路径寻找资源(静态资源文件夹)
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/",
"/"
- 欢迎页,静态资源文件夹下的所有index.html页面
- 图标,**/favicon.ico都在静态资源文件夹下查找
springboot thymeleaf模板引擎
- 引入starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 导入名称空间(非必须):<html lang="en" xmlns:th="http://www.thymeleaf.org">
- 语法
- th:html属性: 改变html的属性
- 基础标签
| 标签 | 功能 | 类比jsp标签 |
1 | th:insert | 插入子片段 | jsp:include |
2 | th:replace | 替换当前节点片段 | jsp:include |
3 | th:each | 遍历 | c:forEach |
4 | th:if | 条件判断 | c:if |
5 | th:unless | 条件判断 | c:if |
6 | th:switch | 条件判断 | c:when |
7 | th:case | 条件判断 | c:choose |
8 | th:object | 申明变量 | c:set |
9 | th:with | 申明变量 | c:set |
10 | th:attr | 属性修改 | |
11 | th:attrprepend | 任意属性修改 | |
12 | th:attrappend | 任意属性修改 | |
13 | th:value | 修改value属性 | |
14 | th:href | 修改href属性 | |
15 | th:src | 修改src属性 | |
16 | th:text | 修改text属性(不转意),行内写法[[...]] | |
17 | th:utext | 修改text属性(转义)行内写法[(...)] | |
18 | th:fragment | 申明片段 | |
19 | th:remove | 移除片段 | |
- 表达式
- ${...}获取变量值,底层是ognl表达式
- 获取对象的属性,调用方法
- 可使用字面变量,文本操作,数学运算,逻辑判断,条件运算
- 内置基本对象
- #ctx
- #vars
- #locale
- #request
- #response
- #session
- #servletContext
- param
- session
- application
- -代表无操作
- 内置工具对象
- #number
- #string
- *{...}和${..}功能一样,可配合th:object提出共有部分
- #{...}获取国际化内容
- @{...}定义url链接
- <a class="form-signin" th:action="@{localhost:8080/version/login/login}">
- <a class="form-signin" th:action="@{/login/login(user=${user}, pass=${pass})}">
- ~{...}片段引用表达式:<div th:insert=~{commons :: main}>...</div>
springmvc auto-configuration
- ContentNegotiatingViewResolver和BeanNameViewResolver
- 自动配置了ViewResolver(视图解析器),视图解析对象决定如何渲染(重定向还是转发)
- ContentNegotiatingViewResolver组合所有的视图解析器
- 定制视图解析器: 给容器中添加一个自定义的ViewResolver(视图解析器),自定义的ViewResolver实现ViewResolver接口
- webjars
- 静态首页index.html访问
- favicon.ico
- 自动注册了Converter,GenericConverter,Formatter组件
- Converter:转换器,view和controller类型转换时使用
- Formatter:格式化器,转换日期格式时使用,生效条件
- 添加格式化器,转换器的方法,如果自定义,则需要往容器里添加Converter的实现
@Override
public void addFormatters(FormatterRegistry registry) {
for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
registry.addConverter(converter);
}
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
registry.addConverter(converter);
}
for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
registry.addFormatter(formatter);
}
}
- HttpMessageConverter
- springmvc用来转换http请求和响应的
- @ResponseBody时Object-->Json
- @RequestBody时json-->Object
- 自定义HttpMessageConverter转换器:@Bean或@Component加入HttpMessageConverters到容器中
- MessageCodesResolver:定义错误代码生成规则的(jsr303校验)
- ConfigurableWebBindingInitializer:初始化WebDataBinder组件
- 自定义:往容器中加入一个ConfigurableWebBindingInitializer组件
- WebDataBinder的作用:请求数据-->JavaBean
修改springboot的默认的自动配置
- springboot在自动配置时,会先查看容器中是否有用户自定义的配置(@Bean或@Component注入),如果有则使用用户自定义的,如果没有则使用默认配置的;如果该组件是一个列表(ViewResolver),则将用户定义的和默认的组合起来
- springboot中会有很多xxxConfigurer帮助我们扩展自动配置
扩展springmvc
- 编写一个WebMvcConfigurer或WebMvcConfigurerAdapter类型的配置类(@Configuration),并且不能标注@EnableWebMvc
- 原理
- WebMvcAutoConfiguration是springmvc的自动配置类
- 在做其它配置时,会导入@Import(EnableWebMvcConfiguration.class)
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
//@Autowired标注会从容器中获取参数的值
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
//将WebMvcConfiguration相关配置一起调用
//public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
// if (!CollectionUtils.isEmpty(configurers)) {
// this.delegates.addAll(configurers);
// }
//}
}
}
}
- 所有的WebMvcConfiguration一起起作用
- 我们的配置类也会起作用
- 配置添加@EnableWebMvc会全面接管springmvc,springmvc的自动配置全部失效(最好不要用),原理如下
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
}
- @EnableWebMvc将WebMvcConfigurationSupport导入进来,只具有springmvc的基础功能
国际化
- 编辑国际化配置文件
- 使用ResourceBundleMessageSource管理国际化资源文件
- springboot自动配置
@Configuration
@ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
@Bean
public MessageSource messageSource() {
MessageSourceProperties properties = messageSourceProperties();
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) {
//设置基础名(去掉国家代码)
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(properties.getBasename())));
}
if (properties.getEncoding() != null) {
messageSource.setDefaultEncoding(properties.getEncoding().name());
}
messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
Duration cacheDuration = properties.getCacheDuration();
if (cacheDuration != null) {
messageSource.setCacheMillis(cacheDuration.toMillis());
}
messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
return messageSource;
}
}
- 在页面使用fmt:message取出国际化内容
- 使用#{common.loginUser}获取
- 根据用户选择获取,使用LocalResolver设置,默认根据请求头信息里的语言设置
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
}
restfulCRUD
- URL格式: /资源名称/资源标识 HTTP请求方式区分对资源的crud操作
- 请求方式
查询 | GET |
增加 | POST |
修改 | PUT |
删除 | DELETE |
thymeleaf布局
- 抽取公共片段
- 引入片段
- ~{模板名::选择器名(变量1,变量2...)}
- ~{模板名::片段名(变量1=值1,变量2=值2)}
- 模板名遵循thymeleaf规则
- th:insert是在当前节点下插入一个子节点,子节点的内容就是该片段
- th:replace是用该片段的内容替换当前节点的内容
- th:include是将该片段的内容包含到当前节点中(不包含片段的最外层标签)
- th:insert可使用[[~{...}]]和[(...)]行内写法
springboot发送其它请求方式
- springmvc中配置HiddenHttpMethodFilter,已自动配置好
- form表单使用post方式
- 创建一个input项,name为_method,value为put,不区分大小写
错误处理机制
- 浏览器默认返回一个错误页面
- 其它客户端默认返回json数据
- 原理
- ErrorMvcAutoConfiguration配置
public class DefaultErrorAttributes implements ErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request,
boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", new Date());
errorAttributes.put("path", request.path());
Throwable error = getError(request);
HttpStatus errorStatus = determineHttpStatus(error);
errorAttributes.put("status", errorStatus.value());
errorAttributes.put("error", errorStatus.getReasonPhrase());
errorAttributes.put("message", determineMessage(error));
handleException(errorAttributes, determineException(error), includeStackTrace);
return errorAttributes;
}
}
- 给容器中添加了以下组件
- DefaultErrorAttributes: 响应错误数据,json格式
- BasicErrorController: 处理/error请求
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
@RequestMapping(produces = "text/html")//html数据,响应浏览器
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
//响应的页面地址
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
/**
protected ModelAndView resolveErrorView(HttpServletRequest request,
HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
for (ErrorViewResolver resolver : this.errorViewResolvers) {
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}
*/
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
@RequestMapping
@ResponseBody//json数据,响应其它客户端
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<>(body, status);
}
}
- ErrorPageCustomizer: 发生错误就会来到/error请求
public class ErrorProperties {
/**
* Path of the error controller.
*/
@Value("${error.path:/error}")
private String path = "/error";
}
- DefaultErrorViewResolver: 决定去哪个页面
public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
Map<String, Object> model) {
ModelAndView modelAndView = resolve(String.valueOf(status), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map<String, Object> model) {
//去到/error/4xx页面
String errorViewName = "error/" + viewName;
//模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
.getProvider(errorViewName, this.applicationContext);
//解析成功
if (provider != null) {
return new ModelAndView(errorViewName, model);
}
//解析失败,就去静态资源文件夹下找errorViewName页面,error/4xx.html
return resolveResource(errorViewName, model);
}
}
- 定制错误响应
- 定制错误页面
- 有模板引擎: 去到error/状态码页面,可使用error/4xx和error/5xx表示,精确匹配优先
- 页面能获取到信息DefaultErrorAttributes决定
- timestamp: 时间戳
- status: 状态码
- error: 错误提示
- exception: 异常对象
- message: 异常信息
- errors: jsr303数据校验错误的信息
- 没有模板引擎: 在静态资源文件夹下查找
- 以下页面都没有,则返回springboot默认的页面
- 定制错误json数据
- 方式一: 编写一个ErrorController实现,放容器中
- 方式二: 自定义一个ErrorAttributes放入到容器中
配置嵌入式的servlet容器
- 修改容器相关的配置: server.xxx修改通用配置,servlet.tomcat.xxx修改和tomcat相关的配置
- 切换容器: 排除默认的tomcat,引入需要的容器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除默认的tomcat容器-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--性能较高,不支持jsp页面-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
- 容器自动配置原理
//自动配置类
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
public static class BeanPostProcessorsRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
}
}
//根据导包选择使用的容器
@Configuration
class ServletWebServerFactoryConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class,
search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
return new UndertowServletWebServerFactory();
}
}
}
//undertow容器工厂
public class UndertowServletWebServerFactory extends AbstractServletWebServerFactory
implements ConfigurableUndertowWebServerFactory, ResourceLoaderAware {
protected UndertowServletWebServer getUndertowWebServer(Builder builder,
DeploymentManager manager, int port) {
return new UndertowServletWebServer(builder, manager, getContextPath(),
isUseForwardHeaders(), port >= 0, getCompression(), getServerHeader());
}
}
//undertow容器
public class UndertowServletWebServer implements WebServer {
public UndertowServletWebServer(Builder builder, DeploymentManager manager,
String contextPath, boolean useForwardHeaders, boolean autoStart,
Compression compression, String serverHeader) {
this.builder = builder;
this.manager = manager;
this.contextPath = contextPath;
this.useForwardHeaders = useForwardHeaders;
this.autoStart = autoStart;
this.compression = compression;
this.serverHeader = serverHeader;
}
@Override
public void start() throws WebServerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
try {
if (!this.autoStart) {
return;
}
if (this.undertow == null) {
this.undertow = createUndertowServer();
}
this.undertow.start();
this.started = true;
UndertowServletWebServer.logger
.info("Undertow started on port(s) " + getPortsDescription()
+ " with context path '" + this.contextPath + "'");
}
catch (Exception ex) {
try {
if (findBindException(ex) != null) {
List<Port> failedPorts = getConfiguredPorts();
List<Port> actualPorts = getActualPorts();
failedPorts.removeAll(actualPorts);
if (failedPorts.size() == 1) {
throw new PortInUseException(
failedPorts.iterator().next().getNumber());
}
}
throw new WebServerException("Unable to start embedded Undertow", ex);
}
finally {
stopSilently();
}
}
}
}
}
注册三大组件
- servlet使用ServletRegistrationBean注册
- filter使用FilterRegistrationBean注册
- listener使用ServletListenerRegistrationBean注册
- 三大组件的注册方式相同
- springboot自动注册DispatcherServlet前端控制器
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
@Configuration
@Conditional(DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@Import(DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class,
name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(
dispatcherServlet, this.webMvcProperties.getServlet().getPath());
//默认拦截所有请求(/),不包括jsp,/*包含jsp请求
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(
this.webMvcProperties.getServlet().getLoadOnStartup());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
}
}
使用外置容器
- 创建war项目,并使用idea生成目录结构
- 配置jsp模板规则
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
- 将嵌入式的容器指定为provider方式
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provider</scope>
</dependency>
- 和ServiceApplication(springboot主程序)同级必须有一个SpringBootServletInitializer类
//运行springboot主程序类
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ServiceApplication.class);
}
}
springboot运行原理
- jar包: 执行springboot主程序的主方法,启动ioc容器,创建嵌入式的servlet容器
- war包: 启动servlet容器,servlet容器启动springboot的主程序方法,启动ioc容器
整合mybatis框架
- 导入mybatis包
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
- 写*Mapper接口,需要使用@mapper标注或主程序上使用@MapperScan("*Mapper接口所在包")
- 注解版: 直接在写的接口上使用@Select,@Delete,@Insert,@Update写sql语句
- 配置文件版: 写一个全局配置文件和sql映射文件,并在springboot配置文件中指定mybatis配置文件所在地点
- 注解版可通过ConfigurationCustomizer自定义mybatis配置
- 配置文件版直接在mybatis配置文件中自定义mybatis配置
springboot运行流程
- 几个重要的事件回调机制
- ApplicationContextInitializer,配置在类路径下的META-INF/spring.factories中
- SpringApplicationRunListener,配置在类路径下的META-INF/spring.factories中
- ApplicationRunner,加入到ioc容器中,使用@Component注解
- CommandLineRunner,加入到ioc容器中,使用@Component注解
- 创建SpringApplication对象
public class SpringApplication {
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//保存主配置类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
判断是否web应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从类路径下找到META-INF/spring.factories配置的所有ApplicationListener,然后保存起来
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//找到主配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
}
- 运行run方法
public class SpringApplication {
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取SpringApplicationRunListeners,从类路径下找到META-INF/spring.factories获取
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
/**
*准备环境
*创建环境,完成后回调SpringApplicationRunListener.environmentPrepared()方法,环境准备完成
*/
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
//打印banner图形
Banner printedBanner = printBanner(environment);
//创建ioc容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
/**
*准备上下文环境
*将environment保存到ioc中
*通过applyInitializers(context)回调所有的ApplicationContextInitializer.initialize()方法
*通过listeners.contextPrepared(context);回调SpringApplicationRunListener.contextPrepared(context)方法
*最后回调SpringApplicationRunListener.contextLoaded(context)方法
*/
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新容器,ioc容器初始化
refreshContext(context);
//从ioc容器中依次获取ApplicationRunner和CommandLineRunner回调
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//回调所有SpringApplicationRunListener.started(context)方法
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);
}
//启动完成,返回ioc容器
return context;
}
}
自定义starter启动器
- 编写自动配置
@Configuration //指定该类是一个配置类
@ConditionalOnWebApplication(type = Type.SERVLET) //判断web应用
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) //有Servlet类
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) //没有WebMvcConfigurationSupport类
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) //指定顺序
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class,ValidationAutoConfiguration.class }) //指定顺序
public class WebMvcAutoConfiguration {
@Configuration
@Import(EnableWebMvcConfiguration.class)
//让xxxProperties生效并加入到容器中
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {
}
}
@ConfigurationProperties(prefix = "spring.mvc") //结合xxxProperties绑定相关配置
public class WebMvcProperties {
}
//自定配置类需要放在类路径下的META-INF/spring.factories中才能自动加载
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
- 模式
- 启动器starter是一个空的jar文件,紧提供辅助性的依赖管理
- 名称约定
- 启动器
- 官方: spring-boot-starter-web
- 自定义: mybatis-spring-boot-starter
- 自动配置: xxx-autoconfigurer
- 步骤
- 编写一个[模块名-spring-boot-starter]模块,引用[模块名-spring-boot-starter-autoconfigurer]模块
- 编写一个[模块名-spring-boot-starter-autoconfigurer]模块
- 编写xxxService处理业务逻辑
public class HelloService {
HelloProperties helloProperties;
public String sayHello(String name){
return helloProperties.getPrefix() + "==>" + name + "<==" + helloProperties.getSuffix();
}
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
}
- 编写xxxServiceAutoConfiguration
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
@Autowired
HelloProperties helloProperties;
@Bean
public HelloService helloService(){
HelloService helloService = new HelloService();
helloService.setHelloProperties(helloProperties);
return helloService;
}
}
- 编写xxxServiceProperties绑定配置文件
@ConfigurationProperties(prefix = "jiyu.hello")
public class HelloProperties {
private String prefix = "";
private String suffix = "";
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
- 在类路径下的META-INF/spring.factories加入HelloServiceAutoConfiguration类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.version.starter.HelloServiceAutoConfiguration
- 在需要使用地点引用该starter即可使用