##SpringBoot优点:
快速创建独立运行的zspring项目以及主流框架的集成使用嵌入式的Servlet容器,应用无需达成WAR包starters自动依赖与版本控制大量的自动配置,简化开发,也可以修改默认值无需配置XML,无代码生成,开箱即用准生产环境的运行时应用监控与云计算的天然集成2014,martin fowler 微服务 :架构风格 一个应用应该是小型服务;可以通过HTTP的方式进行交互
每一个功能元素最终都是一个可独立替换和独立升级的软件单元
@SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
Spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类, SpringBoot就应该运行这个类的main方法来启动SpringBoot应用 SpringApplication.run(主程序类名.class,args);@SpringBootConfiguration:Spring Boot配置类 标注在某个类上,表示这是一个Spring Boot的配置类; @Configuration:配置类上来标注这个注解 配置类 -----配置文件 配置类也是容器中的一个组件:@Component
@EnableAutoConfiguration:开启自动配置功能 以前我们需要配置的东西,Spring Boot帮我们开启自动配置; @EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;
@AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {AutoConfigurationPackage:自动配置包 @Import({Registrar.class}) Spring的底层注解@import,给容器导入一个组件;导入的组件由{Registrar.class};将主配置类(@SpringBootApplication标注的类)的所在的包及下面所有子包里面所有的组件扫描到Spring容器;
Import(EnableAutoConfigurationImportSelector.class); 给容器中导入组件? EnableAutoConfigurationImportSelector:导入那些组件的选择器; 将所有需要导入的组件以全类名的方式返回;这些组件就会被添加搭配容器里 会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件; 有了自动配置类,免去了我们手动编写配置注入功能组件等的工作SpringFactoriesLoader。loadFactoryName(EnableAutoConfiguration.class,classLoader); spring Boot 在启动的时候从类路径下的META-INF/spring.factories获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作以前我们需要自己配置的东西,自动配置类都帮我们;J2EE的整体整合解决方案和自动配置都在E:\jar\maven_repository\maven_repository\org\springframework\boot\spring-boot-autoconfigure\1.5.9.RELEASE\spring-boot-autoconfigure-1.5.9.RELEASE.jar
1.POM文件 1.父项目
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent>他的父项目:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.9.RELEASE</version> <relativePath>../spring-boot-dependencies</relativePath> </parent> 注:他来真正管理Spring Boot应用里面的所有依赖版本 Spring Boot的版本仲裁中心; 以后我们导入以来默认是不需要写版本;(没有在dependencies里面管理的依赖自然需要声明版本号)2.导入的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>spring-boot-starter-web:
spring-boot-starte:spring-boot场景启动器;帮我们导入了web模板正常运行所以来的组件;Spring Boot将所有的功能场景都抽取出来,做成一个个starters(启动器),只需要在项目里面引入这些starter相关场景的所有依赖都会导入进来,要用什么功能就导入什么场景的启动器@RestController是//@Controller@ResponseBody(//这个类所有的方法返回的数据直接写给浏览器(如果是对象转为json数据))的合体
IDE都支持使用Spirng的项目创建向导快速创建一个Spring Boot项目; 选择我们需要的模块;向导会联网创建Spring Boot项目; 默认生成的Spring Boot项目;
主程序已经生成好了,我们只需要我们自己的逻辑resources文件夹中的目录结构 static:保存所有的静态资源;js css imagestemplates:保存所有的模板页面;(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面);可以使用模板引(freemarker,thymeleaf)application.properties:Spring Boot应用的配置文件; 可以修改一些默认设置YAML Ain`t Markup Language
YAML A Markup Language :是一个标记语言YAML isn`t Markup Language:不是一个标记语言标记语言:
以前的配置文件:大多都是使用xxx.xml文件YAML:以数据为中心,比json,xml等更适合做配置文件1.YAML基本语法 k:(空格)v:表示一对键值对(空格必须有)
使用缩进表示层级关系;只要是左对齐的一列数据,都是同一级的缩进时不允许使用Tab键,只允许使用空格缩进的空格数目不重要,只要相同层级的元素左侧对其即可属性和值大小写敏感2.YAML支持的三种数据结构
对象(属性和值):键值对的集合数组:一组按次序排列的值字面量:单个的,不可再分的值(数字,字符串,布尔) k:v :字面直接来写; 字符串默认不要加上单引号或者双引号 “”:双引号不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思 ‘’:单引号 会转义特殊字符,特殊字符最终只是一个普通的字符串数据对象,Map(属性和值)(键值对): k:v: 对象还是k:v的方式
friends: lastName:zhangsan age:20 行内写法: friends:{lastName:zhangsan,age:18}数组(list,Set) 用**-空格**值表示数组中的一个元素
pets: - cat - dog - pig行内写法
pets:[cat,dog,pig]将配置文件中配置的每一个属性的值,映射到这个组件中 @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中得相关的配置进行绑定; 只有这个组件是容器中的组件,才能使用容器提供的@Configurationproperties功能 需要加一个@Component prifix=“person” 配置文件中那个下面属性进行一一映射 默认从全局配置文件中获取值 导入配置文件处理器,配置文件进行绑定就会有提示
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>2.@value获取值和@ConfigurationProperties获取值比较
@ConfigurationProperties@value功能批量注入配置文件中的属性一个个指定松散语法绑定支持不支持SpEL不支持支持JSR303数据校验支持不支持复杂类型封装支持不支持配置文件yml还是properties他们都能获取到值; 如果说,我们只是在某个业务逻辑中需获取一下配置文件中的某项值,使用@Value; 如果说,我们专门编写了一个JavaBean来和配置文件进行映射,我们就直接使用 @ConfigurationProperties
@PropertySource(value={“classpath:”})读取类路径下指定的文件@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效; Spring Boot里面没有Spring的配置文件,我们字节编写的配置文件,也不能自动识别;想让Spring的配置文件生效,加载进来,需要**@ImportResource**标注在一个配置类上RandomValuePropertySource:配置文件中可以使用随机数
${random.value}${random.int}${random.long}${random.int(10)}${random{1024,65536}}属性配置占位符 app.name=MyApp app.description=${app.name} is a Spring Boot application
可以在配置文件中引用前面配置过的属性(优先级前面配置过得这里都能用)${app.name:默认值} 来指定找不到属性时的默认值Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活,指定参数等方式快速切换环境
1.多Profile文件形式 我们可以在主配置文件编写的时候,文件名可以是application-{profile}.properties/yml 默认使用application.properties的配置
- 格式:application-{profile}.properties: - application-dev.properties,application-prod.properties2.多profile文档块模式: 3.激活方式:
命令行 --spring.profiles.active=dev在配置文件中指定 spring.profiles.active=dev配置文件 spring.profiles.active=devjvm参数 -Dspring.profiles.active=devSpring Boot支持多种外部配置的顺序 springBoot也课题从以下位置加装配置;优先级从高到低,高优先级的配置覆盖低优先级的配置,所有的配置形成互补配置
命令行参数来自java:comp/env的JND属性Java系统属性(System.getProperties())操作系统环境变量RandomValuePropertySource配置的random.*属性值jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件jar包外部的application.properties或啊application.yml(不带spring.profile)配置文件jar包内部的application.properties或啊application.yml(不带spring.profile)配置文件@Configuration注解类上的@propertySource通过SpringApplication.setdefaultProperties指定的默认文件注:由jar包外向jar包内寻找;优先加装带profile 多个配置用空格分开: --配置项=值
利用 EnableAutoConfigurationImportSelectorgeoron给容器中导入一些组件
可以查看selectImports()方法的内容;
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置
SpringFactoriesLoader.loadFactoryNames扫描所有jar包类路径下META-INF/spring.factories把扫描到的这些文件的内容包装成properties对象从properties中获取EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加到容器中将类路径下META-INF/spring.factories里面配置的所有EnableAutoConfiguration的值加入到容器中
每一个这样的xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置
3.每一个自动配置类进行自动配置功能
4.以 HTTPEnableAutoConfiguration(http编码自动配置)为例解释自动配置原理:
@Configuration( == //表示这是一个配置类,以前编写的配置文件一样,也可以给容器添加组件== proxyBeanMethods = false ) @EnableConfigurationProperties({HttpEncodingProperties.class}) //启用指定类的ConfigurationProperries功能;将配置文件中对应的值和HttpEncodingProperties绑定起来,并把HttpEncodingProperties加入到ioc容器中 @ConditionalOnWebApplication( //spring底层@Conditional注解根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效 ; 判断当前应用是否是web应用,如果是当前配置类生效 type = Type.SERVLET ) @ConditionalOnClass({CharacterEncodingFilter.class}) //判断当前项目有没有这个类 CharacterEncodingFilter:SpringMVC中进行乱码解决的过滤器 @ConditionalOnProperty( // 判断配置文件中是否存在某个配置spring.http.encoding.enable; 如果不存在,判断也成立 即使我们配置文件中不配置 // spring.http.encoding.enable=ture 也是默认生效 prefix = “spring.http.encoding”, value = {“enabled”}, matchIfMissing = true ) public class HttpEncodingAutoConfiguration {
他已经和Sopringboot的配置文件映射了 private final Encoding properties;
只有一个有参构造器的情况下,参数的值就会从容器里拿 public HttpEncodingAutoConfiguration(HttpProperties properties) { this.properties = properties.getEncoding(); }
@Bean 给容器中添加一个组件,这个组件的值需要从properties中获取 @ConditionalOnMissingBean public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(this.properties.getCharset().name()); filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE)); return filter; }
根据当前不同的条件判断,决定这个配置类是否生效?
一旦这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性 又和配置文件绑定的;
5.所有在配置文件中能配置的属性都是在xxxProperties类中封装着;配置文件能配置什么就可以参照某个功能对应的这个属性类 >@ConfigurationProperties( //从配置文件中获取指定的值和bean的属性继续绑定 prefix = "spring.http" )<精髓:
1.SpringBoot启动会加载大量的配置类 2.我们看我们需要的功能有没有SpringBoot默认写好的自动配置类 3.我们再来开这个自动配置类中到底配置了那些组件(只要我们要用的组件有,我们就不需要再来配置了) 4.给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们就可以在配置文件中指定这些属性的值xxxAutoConfiguration:制动配置类 给容器中添加组件 xxxProperties:封装配置文件中相关的属性
##细节
1.@Conditional派生注解 作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置类里面的所有内容才会生效 @Conditional扩展注解作用(判断是否满足当前指定条件)@ConditionalOnJava系统的java版本是否满足条件@ConditionalOnBean容器中存在指定Bean@ConditionalOnMissingBean容器中不存在指定Bean@ConditionalOnExpression满足SpEL表达式指定@ConditionalOnClass系统有指定类@ConditionalOnMissingClass系统中没有指定类@ConditionalOnSingleCandidate容器中只有一个指定Bean或者这个Bean是首选的Bean@ConditionalOnProperty系统中指定的属性是否有指定的值@ConditionalOnResource类路径下是否有指定的资源文件@ConditionalOnWebApplication当前是web环境@ConditionalOnNotWebApplication当前不是webn环境@ConditionalOnJndiJNDI存在指定项开启SpringBoot的debug application.properties中写入debug=true来让控制台打印自动配置报告,这样就能很方便知道哪些自动配置生效 自动配置类必须在一定的条件下才能生效 Positive matches:(自动配置类启用的) Nrgative mathes:(没有启动,没有匹配成功的自动配置类)
SpringBoot 日志门面(日志的抽象层):SLF4J 日志实现:Logback
以后开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法; 给系统里面导入slf4j的jar和logback的实现jar
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HelloWorld { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(HelloWorld.class); logger.info("Hello World"); } }每一个日志的实现框架都有自己的配置文件。使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件
springBoot使用他来做日志功能
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency>总结
SpringBoot地层也是使用slf4j+logback的方式进行日志记录SpringBoot也把其他的日志都替换成了slf4j中间替换包如果我们要引入其他的框架,一定要把这个框架的默认日志依赖移除掉SpringBoot能自动适配所有的日志,而且底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架的日志框架移除掉
记录器
Logger logger =LoggerFactory.getLogger(getClass());
日志的级别
由低到高 trace<debug<info<warn<error 可以调整输出的日志级别;日志就只会在这个级别之后的高级别生效 springBoot默认给我们使用的是info级别的;没有指定级别的就用S平日ingBoot默认规定的级别;root级别
日志输出格式:
%d表示时间%thread表示线程名%-5level:级别从做显示五个字符宽度%logger{50}表示logger名字长50个字符,否者按句号点分割%msg:日志信息%n是换行符%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n不指定路径在当前项目下生成springboot.log日志 可以指定完整的路径 logging.file= 在控制台输出日志的格式 logging.pattern.console= 指定文件中日志输出的格式 logging.pattern.file=
给类路径下放上每个日志框架自己的配置文件即可;SpringBoot就不会使用其他的默认配置
Logging SystemCustomizationLogbacklogback-spring.xml ,logback-spring.groovy,logback.xml or logback.groovtLog4j2log4j2-spring.xml or log4j2.xmlJDK(Java Util Logging)logging.propertieslogback.xml:直接就被日志框架识别了 logback-spring.xml:日志框架就不直接加载日志的配置项,由springboot解析日志配置,可以使用SpringBoot的高级profile功能
<springProfile name="staging"> <!--configuration to be enable when the "staging" profile is active--> 可以指定某段配资只在某个环境下生效 </springProfile>否则
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <!-- 日志输出格式: %d表示日期时间, %thread表示线程名, %-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息, %n是换行符 --> <layout class="ch.qos.logback.classic.PatternLayout"> <springProfile name="dev"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern> </springProfile> <springProfile name="!dev"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern> </springProfile> </layout> </appender>使用SpringBoot
创建一个SpringBoot应用,选中我们需要的模块;SpringBoot已经默认将这些场景配置好了,只需要在配置文件中制定少量配置就可以运行起来自己编写业务代码自动配置原理? 这个场景SpringBoot帮我们配置什么?能不能修改?能修改那些配置?能不能扩展?xxx
xxxxAutoConfiguration:帮我们给容器中自动配置组件xxxxproperties:配置类来封装配置文件的内容可以设置静态资源的有关的参数,缓存时间等
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl(); if (!registry.hasMappingForPattern("/webjars/**")) { customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/") .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())) .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } } //配置欢迎页映射 @Bean public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext) { return new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(), this.mvcProperties.getStaticPathPattern()); } @Configuration @ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true) public static class FaviconConfiguration implements ResourceLoaderAware { private final ResourceProperties resourceProperties; private ResourceLoader resourceLoader; public FaviconConfiguration(ResourceProperties resourceProperties) { this.resourceProperties = resourceProperties; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @Bean public SimpleUrlHandlerMapping faviconHandlerMapping() { SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", faviconRequestHandler())); return mapping; } //配置喜欢的图标 @Bean public ResourceHttpRequestHandler faviconRequestHandler() { ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler(); requestHandler.setLocations(resolveFaviconLocations()); return requestHandler; } private List<Resource> resolveFaviconLocations() { String[] staticLocations = getResourceLocations(this.resourceProperties.getStaticLocations()); List<Resource> locations = new ArrayList<>(staticLocations.length + 1); Arrays.stream(staticLocations).map(this.resourceLoader::getResource).forEach(locations::add); locations.add(new ClassPathResource("/")); return Collections.unmodifiableList(locations); } } }所有/webjars/**,都去classpath:/META-INF/resources/webjars/找资源 webjars:以jar包的方式引入静态资源
“/**” 访问当前项目的任何资源(静态资源文件夹)
“classpath:/META-INF/resources/”,“classpath:/resources/”,“classpath:/static/”,“classpath:/public/”“/”:当前项目下的根路径 localhost:8080/abc === 去静态资源文件夹下找abc -欢迎页;静态资源文件夹下的所有index.html页面;被"/**"映射; localhost:8080/ 找index页面所有的"**/favicon.ico"都是在静态文件夹下找
JSP VElocity Freemarker Thymeleaf SpringBoot推荐的Thymeleaf 语法更简单,功能更强大
使用:
导入thtmeleaf的名称空间语法 th:text 将div里面的文本内容设置为2.表达式
❤Simple expressions: Variable Expressions: ${...} 获取变量值;OGNL; 1.获取对象的属性,调用方法 2.使用内置的基本对象 #ctx : the context object. #vars: the context variables. #locale : the context locale. #request : (only in Web Contexts) the HttpServletRequest object. #response : (only in Web Contexts) the HttpServletResponse object. #session : (only in Web Contexts) the HttpSession object. #servletContext : (only in Web Contexts) the ServletContext object 3.内置的一些工具对象 #execInfo : information about the template being processed. #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax. #uris : methods for escaping parts of URLs/URIs Page 20 of 106 #conversions : methods for executing the configured conversion service (if any). #dates : methods for java.util.Date objects: formatting, component extraction, etc. #calendars : analogous to #dates , but for java.util.Calendar objects. #numbers : methods for formatting numeric objects. #strings : methods for String objects: contains, startsWith, prepending/appending, etc. #objects : methods for objects in general. #bools : methods for boolean evaluation. #arrays : methods for arrays. #lists : methods for lists. #sets : methods for sets. #maps : methods for maps. #aggregates : methods for creating aggregates on arrays or collections. #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration). Selection Variable Expressions: *{...} 选择表达式:和${}在功能上一样; ❤补充:配合 th:object="${session.user}" <div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div> Message Expressions: #{...} 获取国际化内容 Link URL Expressions: @{...} 定义URL @{/order/process(execId=${execId},execType='FAST')} Fragment Expressions: ~{...} 片段引用表达式 <div th:insert="~{commons :: main}">...</div> ❤Literals (字面量) Text literals: 'one text' , 'Another one!' ,… Number literals: 0 , 34 , 3.0 , 12.3 ,… Boolean literals: true , false Null literal: null Literal tokens: one , sometext , main ,… ❤Text operations: (文本操作) String concatenation: + Literal substitutions: |The name is ${name}| ❤Arithmetic operations:(数学运算) Binary operators: + , - , * , / , % Minus sign (unary operator): - ❤Boolean operations:(布尔运算) Binary operators: and , or Boolean negation (unary operator): ! , not ❤Comparisons and equality:(比较运算) Comparators: > , < , >= , <= ( gt , lt , ge , le ) Equality operators: == , != ( eq , ne )(三元运算符) ❤Conditional operators:(条件运算) If-then: (if) ? (then) If-then-else: (if) ? (then) : (else) Default: (value) ?: (defaultvalue) ❤Special tokens:(特殊操作) No-Operation编写一个配置类(@Configuation) ,是WebMvcConfigurerAdapter类型;不能标注@EnableWebMvc 既保留看所有的自动配置,也能用我们扩展的配置
原理: 1.WebMvcAutoConfiguration是SpringMvc的自动配置类 2.在做其他自动配置时会导入@Import(EnableWebMvcConfiguration.class)
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); //从容器中获取所有的WebMvcConfigurer @Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); //一个参考实现,将所有的WebMvcConfigurer相关配置都来一起调用 @Override public void addFormatters(FormatterRegistry registry) { for (WebMvcConfigurer delegate : this.delegates) { delegate.addFormatters(registry); } } } }3.容器中所有耳朵WebMvcConfigurer都会起作用 4.我们的配置类也会被调用 效果:SpringMvc的自动配置也会和我们的扩展配置都会作用
SpringBoot对SpringMVC的自动配置不需要了,所有的都是我们自己配;所有的SpringMvc场景自动配置都失效 我们只需要在配置类中添加@EnableWebMvc即可; 原理: 为什么@EnableWebMvc自动配置就失效了 1.@EnableWebMvc核心
@Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc { }2.、
@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, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration {4.@EnableWebMvc将WebMvcConfigurationSupport组件导入进来; 5.导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能
模式:
1.SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean,@Component) 如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置和自己 默认的组合起来 2.在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置1.默认访问首页
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能 //@EnableWebMvc 不要接管SpringMVC @Configuration public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { // super.addViewControllers(registry); //浏览器发送 /atguigu 请求来到 success registry.addViewController("/atguigu").setViewName("success"); } //所有的WebMvcConfigurerAdapter组件都会一起起作用 @Bean //将组件注册在容器 public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){ WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("login"); registry.addViewController("/index.html").setViewName("login"); } }; return adapter; } }1.编写国际化配置文件 2.使用ResourceBundleMessageSource管理国际化资源文件 3.在页面使用fmt:message取出国际化内容
步骤
1.编写国际化配文件,抽取页面需要显示的国际化消息原理
可以参考ErrorMVCAutoConfiguration;错误处理的自动配置 给容器中添加了一下组件 1.DefaultErrorAttribute 2.BasicErrorController 3.ErrorPageCustomizer 4.DefaultErrorViewResolver步骤: ·一旦系统出现4xxx或者5xx之类的错误;ErrorPageCustomizer就会生效()