tags:
45、web实验-抽取公共页面
- 公共页面
/templates/common.html
1 |
|
/templates/table/basic_table.html
1 |
|
Difference between th:insert
and th:replace
(and th:include
)
46、web实验-遍历数据与页面bug修改
控制层代码:
1 |
|
页面代码:
1 | <table class="display table table-bordered" id="hidden-table-info"> |
47、视图解析-【源码分析】-视图解析器与视图
视图解析原理流程:
- 目标方法处理的过程中(阅读
DispatcherServlet
源码),所有数据都会被放在ModelAndViewContainer
里面,其中包括数据和视图地址。 - 方法的参数是一个自定义类型对象(从请求参数中确定的),把他重新放在
ModelAndViewContainer
。 - 任何目标方法执行完成以后都会返回
ModelAndView
(数据和视图地址)。 processDispatchResult()
处理派发结果(页面改如何响应)render(mv, request, response);
进行页面渲染逻辑- 根据方法的
String
返回值得到View
对象【定义了页面的渲染逻辑】
- 所有的视图解析器尝试是否能根据当前返回值得到
View
对象 - 得到了
redirect:/main.html --> Thymeleaf new RedirectView()
。 ContentNegotiationViewResolver
里面包含了下面所有的视图解析器,内部还是利用下面所有视图解析器得到视图对象。view.render(mv.getModelInternal(), request, response);
视图对象调用自定义的render进行页面渲染工作。
RedirectView
如何渲染【重定向到一个页面】- 获取目标url地址
response.sendRedirect(encodedURL);
- 根据方法的
视图解析:
- 返回值以 forward:
开始: new InternalResourceView(forwardUrl);
–> 转发request.getRequestDispatcher(path).forward(request, response);
- 返回值以 redirect:
开始: new RedirectView()
–> render就是重定向
- 返回值是普通字符串:new ThymeleafView()
—>
阅读源码:最好自己在IDE,打断点,且Debug模式运行实例,这样比较没那么沉闷。
48、拦截器-登录检查与静态资源放行
编写一个拦截器实现
HandlerInterceptor
接口拦截器注册到容器中(实现
WebMvcConfigurer
的addInterceptors()
)指定拦截规则(注意,如果是拦截所有,静态资源也会被拦截】
编写一个实现HandlerInterceptor
接口的拦截器:
1 |
|
拦截器注册到容器中 && 指定拦截规则:
1 |
|
49、拦截器-【源码分析】-拦截器的执行时机和原理
- 根据当前请求,找到
HandlerExecutionChain
(可以处理请求的handler以及handler的所有 拦截器) - 先来顺序执行 所有拦截器的
preHandle()
方法。- 如果当前拦截器
preHandle()
返回为true
。则执行下一个拦截器的preHandle()
- 如果当前拦截器返回为
false
。直接倒序执行所有已经执行了的拦截器的afterCompletion();
。
- 如果当前拦截器
- 如果任何一个拦截器返回
false
,直接跳出不执行目标方法。 - 所有拦截器都返回
true
,才执行目标方法。 - 倒序执行所有拦截器的
postHandle()
方法。 - 前面的步骤有任何异常都会直接倒序触发
afterCompletion()
。 - 页面成功渲染完成以后,也会倒序触发
afterCompletion()
。
DispatcherServlet
中涉及到HandlerInterceptor
的地方:
1 | public class DispatcherServlet extends FrameworkServlet { |
1 | public class HandlerExecutionChain { |
50、文件上传-单文件与多文件上传的使用
- 页面代码
/static/form/form_layouts.html
1 | <form role="form" th:action="@{/upload}" method="post" enctype="multipart/form-data"> |
- 控制层代码
1 |
|
文件上传相关的配置类:
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
文件大小相关配置项:
1 | spring.servlet.multipart.max-file-size=10MB |
51、文件上传-【源码流程】文件上传参数解析器
文件上传相关的自动配置类MultipartAutoConfiguration
有创建文件上传参数解析器StandardServletMultipartResolver
。
1 |
|
1 | //文件上传解析器 |
1 | public class DispatcherServlet extends FrameworkServlet { |
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
跳到以下的类
1 | public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter |
this.argumentResolvers
其中主角类RequestPartMethodArgumentResolver
用来生成
1 | public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { |
1 | public class RequestPartMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver { |
1 | public final class MultipartResolutionDelegate { |
52、错误处理-SpringBoot默认错误处理机制
Spring Boot官方文档 - Error Handling
默认规则:
默认情况下,Spring Boot提供
/error
处理所有错误的映射机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据
1 | { |
要对其进行自定义,添加
View
解析为error
要完全替换默认行为,可以实现
ErrorController
并注册该类型的Bean定义,或添加ErrorAttributes类型的组件
以使用现有机制但替换其内容。/templates/error/
下的4xx,5xx页面会被自动解析
53、错误处理-【源码分析】底层组件功能分析
ErrorMvcAutoConfiguration
自动配置异常处理规则- 容器中的组件:类型:
DefaultErrorAttributes
-> id:errorAttributes
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver
DefaultErrorAttributes
:定义错误页面中可以包含数据(异常明细,堆栈信息等)。
- 容器中的组件:类型:
BasicErrorController
–> id:basicErrorController
(json+白页 适配响应) - 处理默认
/error
路径的请求,页面响应new ModelAndView("error", model);
- 容器中有组件
View
->id是error;(响应默认错误页) - 容器中放组件
BeanNameViewResolver
(视图解析器);按照返回的视图名作为组件的id去容器中找View
对象。
- 容器中有组件
- 容器中的组件:类型:
DefaultErrorViewResolver
-> id:conventionErrorViewResolver
- 如果发生异常错误,会以HTTP的状态码 作为视图页地址(viewName),找到真正的页面(主要作用)。
- error/404、5xx.html
- 如果想要返回页面,就会找error视图(
StaticView
默认是一个白页)。
54、错误处理-【源码流程】异常处理流程
譬如写一个会抛出异常的控制层:
1 |
|
当浏览器发出/hello
请求,DispatcherServlet
的doDispatch()
的mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
将会抛出ArithmeticException
。
1 | public class DispatcherServlet extends FrameworkServlet { |
系统自带的异常解析器:
DefaultErrorAttributes
先来处理异常,它主要功能把异常信息保存到request域,并且返回null。
1 | public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered { |
默认没有任何解析器(上图的
HandlerExceptionResolverComposite
)能处理异常,所以最后异常会被抛出。最终底层就会转发
/error
请求。会被底层的BasicErrorController
处理。
1 |
|
1 | protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { |
1 |
|
55、错误处理-【源码流程】几种异常处理原理
自定义错误页
- error/404.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html;如果都没有就触发白页
@ControllerAdvice
+@ExceptionHandler
处理全局异常;底层是ExceptionHandlerExceptionResolver
支持的
1 |
|
@ResponseStatus
+自定义异常 ;底层是ResponseStatusExceptionResolver
,把responseStatus注解的信息底层调用response.sendError(statusCode, resolvedReason)
,tomcat发送的/error
1 |
|
1 |
|
Spring自家异常如
org.springframework.web.bind.MissingServletRequestParameterException
,DefaultHandlerExceptionResolver
处理Spring自家异常。response.sendError(HttpServletResponse.SC_BAD_REQUEST/*400*/, ex.getMessage());
自定义实现
HandlerExceptionResolver
处理异常;可以作为默认的全局异常处理规则
1 | //优先级,数字越小优先级越高 |
ErrorViewResolver
实现自定义处理异常response.sendError()
,error请求就会转给controller。- 你的异常没有任何人能处理,tomcat底层调用
response.sendError()
,error请求就会转给controller。 basicErrorController
要去的页面地址是ErrorViewResolver
。
1 |
|
1 |
|
56、原生组件注入-原生注解与Spring方式注入
官方文档 - Servlets, Filters, and listeners
使用原生的注解
1 |
|
1 |
|
1 |
|
最后还要在主启动类添加注解@ServletComponentScan
1 | // |
Spring方式注入
ServletRegistrationBean
, FilterRegistrationBean
, and ServletListenerRegistrationBean
1 |
|
57、原生组件注入-【源码分析】DispatcherServlet注入原理
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
配置类
1 |
|
DispatcherServlet
默认映射的是 /
路径,可以通过在配置文件修改spring.mvc.servlet.path=/mvc
。
58、嵌入式Servlet容器-【源码分析】切换web服务器与定制化
默认支持的WebServer
Tomcat
,Jetty
, orUndertow
。ServletWebServerApplicationContext
容器启动寻找ServletWebServerFactory
并引导创建服务器。
原理
- SpringBoot应用启动发现当前是Web应用,web场景包-导入tomcat。
- web应用会创建一个web版的IOC容器
ServletWebServerApplicationContext
。 ServletWebServerApplicationContext
启动的时候寻找ServletWebServerFactory
(Servlet 的web服务器工厂——>Servlet 的web服务器)。- SpringBoot底层默认有很多的WebServer工厂(
ServletWebServerFactoryConfiguration
内创建Bean),如:TomcatServletWebServerFactory
JettyServletWebServerFactory
UndertowServletWebServerFactory
- 底层直接会有一个自动配置类
ServletWebServerFactoryAutoConfiguration
。 ServletWebServerFactoryAutoConfiguration
导入了ServletWebServerFactoryConfiguration
(配置类)。ServletWebServerFactoryConfiguration
根据动态判断系统中到底导入了那个Web服务器的包。(默认是web-starter导入tomcat包),容器中就有TomcatServletWebServerFactory
TomcatServletWebServerFactory
创建出Tomcat服务器并启动;TomcatWebServer
的构造器拥有初始化方法initialize——this.tomcat.start();
- 内嵌服务器,与以前手动把启动服务器相比,改成现在使用代码启动(tomcat核心jar包存在)。
Spring Boot默认使用Tomcat服务器,若需更改其他服务器,则修改工程pom.xml:
1 | <dependency> |
定制Servlet容器
实现
WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
- 把配置文件的值和
ServletWebServerFactory
进行绑定
- 把配置文件的值和
修改配置文件
server.xxx
直接自定义
ConfigurableServletWebServerFactory
xxxxxCustomizer
:定制化器,可以改变xxxx的默认规则
1 | import org.springframework.boot.web.server.WebServerFactoryCustomizer; |
59、定制化原理-SpringBoot定制化组件的几种方式(小结)
定制化的常见方式
修改配置文件
xxxxxCustomizer
编写自定义的配置类
xxxConfiguration
+@Bean
替换、增加容器中默认组件,视图解析器Web应用 编写一个配置类实现
WebMvcConfigurer
即可定制化web功能 +@Bean
给容器中再扩展一些组件
1 |
|
@EnableWebMvc
+WebMvcConfigurer
—@Bean
可以全面接管SpringMVC,所有规则全部自己重新配置; 实现定制和扩展功能(高级功能,初学者退避三舍)。- 原理:
WebMvcAutoConfiguration
默认的SpringMVC的自动配置功能类,如静态资源、欢迎页等。- 一旦使用
@EnableWebMvc
,会@Import(DelegatingWebMvcConfiguration.class)
。 DelegatingWebMvcConfiguration
的作用,只保证SpringMVC最基本的使用- 把所有系统中的
WebMvcConfigurer
拿过来,所有功能的定制都是这些WebMvcConfigurer
合起来一起生效。 - 自动配置了一些非常底层的组件,如
RequestMappingHandlerMapping
,这些组件依赖的组件都是从容器中获取如。 public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
。
- 把所有系统中的
WebMvcAutoConfiguration
里面的配置要能生效必须@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
。- @EnableWebMvc 导致了WebMvcAutoConfiguration 没有生效。
- 原理:
原理分析套路
场景starter - xxxxAutoConfiguration
- 导入xxx组件 - 绑定xxxProperties
- 绑定配置文件项。
60、数据访问-数据库场景的自动配置分析与整合测试
导入JDBC场景
1 | <dependency> |
接着导入数据库驱动包(MySQL为例)。
1 | <!--默认版本:--> |
相关数据源配置类
DataSourceAutoConfiguration
: 数据源的自动配置。- 修改数据源相关的配置:
spring.datasource
。 - 数据库连接池的配置,是自己容器中没有DataSource才自动配置的。
- 底层配置好的连接池是:
HikariDataSource
。
- 修改数据源相关的配置:
DataSourceTransactionManagerAutoConfiguration
: 事务管理器的自动配置。JdbcTemplateAutoConfiguration
:JdbcTemplate
的自动配置,可以来对数据库进行CRUD。- 可以修改前缀为
spring.jdbc
的配置项来修改JdbcTemplate
。 @Bean @Primary JdbcTemplate
:Spring容器中有这个JdbcTemplate
组件,使用@Autowired
。
- 可以修改前缀为
JndiDataSourceAutoConfiguration
: JNDI的自动配置。XADataSourceAutoConfiguration
: 分布式事务相关的。
修改配置项
1 | spring: |
单元测试数据源
1 | import org.junit.jupiter.api.Test; |
61、数据访问-自定义方式整合druid数据源
Druid是什么?
它是数据库连接池,它能够提供强大的监控和扩展功能。
Spring Boot整合第三方技术的两种方式:
自定义
找starter场景
自定义方式
添加依赖:
1 | <dependency> |
配置Druid数据源:
1 |
|
配置Druid的监控页功能:
Druid内置提供了一个
StatViewServlet
用于展示Druid的统计信息。官方文档 - 配置_StatViewServlet配置。这个StatViewServlet
的用途包括:- 提供监控信息展示的html页面
- 提供监控信息的JSON API
Druid内置提供一个
StatFilter
,用于统计监控信息。官方文档 - 配置_StatFilterWebStatFilter
用于采集web-jdbc关联监控的数据,如SQL监控、URI监控。官方文档 - 配置_配置WebStatFilterDruid提供了
WallFilter
,它是基于SQL语义分析来实现防御SQL注入攻击的。官方文档 - 配置 wallfilter
1 |
|
62、数据访问-druid数据源starter整合方式
官方文档 - Druid Spring Boot Starter
引入依赖:
1 | <dependency> |
分析自动配置:
- 扩展配置项
spring.datasource.druid
- 自动配置类
DruidDataSourceAutoConfigure
DruidSpringAopConfiguration.class
, 监控SpringBean的;配置项:spring.datasource.druid.aop-patterns
DruidStatViewServletConfiguration.class
, 监控页的配置。spring.datasource.druid.stat-view-servlet
默认开启。DruidWebStatFilterConfiguration.class
,web监控配置。spring.datasource.druid.web-stat-filter
默认开启。DruidFilterConfiguration.class
所有Druid的filter的配置:
1 | private static final String FILTER_STAT_PREFIX = "spring.datasource.druid.filter.stat"; |
配置示例:
1 | spring: |
63、数据访问-整合MyBatis-配置版
starter的命名方式:
- SpringBoot官方的Starter:
spring-boot-starter-*
- 第三方的:
*-spring-boot-starter
引入依赖:
1 | <dependency> |
配置模式:
全局配置文件
SqlSessionFactory
:自动配置好了SqlSession
:自动配置了SqlSessionTemplate
组合了SqlSession
@Import(AutoConfiguredMapperScannerRegistrar.class)
Mapper
: 只要我们写的操作MyBatis的接口标准了@Mapper
就会被自动扫描进来
1 | : MyBatis配置项绑定类。 |
配置文件:
1 | spring: |
mybatis-config.xml:
1 |
|
Mapper接口:
1 |
|
1 | import com.lun.boot.bean.User; |
POJO:
1 | public class User { |
DB:
1 | CREATE TABLE `user` ( |
Controller and Service:
1 |
|
1 |
|
配置private Configuration configuration;
也就是配置mybatis.configuration
相关的,就是相当于改mybatis全局配置文件中的值。(也就是说配置了mybatis.configuration
,就不需配置mybatis全局配置文件了)
1 | # 配置mybatis规则 |
小结
- 导入MyBatis官方Starter。
- 编写Mapper接口,需
@Mapper
注解。 - 编写SQL映射文件并绑定Mapper接口。
- 在
application.yaml
中指定Mapper配置文件的所处位置,以及指定全局配置文件的信息 (建议:**配置在mybatis.configuration
**)。
64、数据访问-整合MyBatis-注解配置混合版
你可以通过Spring Initializr添加MyBatis的Starer。
注解与配置混合搭配,干活不累:
1 |
|
1 |
|
简单DAO方法就写在注解上。复杂的就写在配置文件里。
使用
@MapperScan("com.lun.boot.mapper")
简化,Mapper接口就可以不用标注@Mapper
注解。
1 |
|
65、数据访问-整合MyBatisPlus操作数据库
MyBatisPlus是什么
MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
添加依赖:
1 | <dependency> |
MybatisPlusAutoConfiguration
配置类,MybatisPlusProperties
配置项绑定。SqlSessionFactory
自动配置好,底层是容器中默认的数据源。mapperLocations
自动配置好的,有默认值classpath*:/mapper/**/*.xml
,这表示任意包的类路径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件。 建议以后sql映射文件放在 mapper下。容器中也自动配置好了
SqlSessionTemplate
。@Mapper
标注的接口也会被自动扫描,建议直接@MapperScan("com.lun.boot.mapper")
批量扫描。MyBatisPlus优点之一:只需要我们的Mapper继承MyBatisPlus的
BaseMapper
就可以拥有CRUD能力,减轻开发工作。
1 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
66、数据访问-CRUD实验-数据列表展示
使用MyBatis Plus提供的IService
,ServiceImpl
,减轻Service层开发工作。
1 | import com.lun.hellomybatisplus.model.User; |
1 | import com.lun.hellomybatisplus.model.User; |
与下一节联合在一起
67、数据访问-CRUD实验-分页数据展示
与下一节联合在一起
68、数据访问-CRUD实验-删除用户完成
添加分页插件:
1 |
|
1 | <table class="display table table-bordered table-striped" id="dynamic-table"> |
#numbers
表示methods for formatting numeric objects.link
1 |
|
69、数据访问-准备阿里云Redis环境
添加依赖:
1 | <dependency> |
RedisAutoConfiguration
自动配置类,RedisProperties 属性类 –> spring.redis.xxx是对redis的配置。- 连接工厂
LettuceConnectionConfiguration
、JedisConnectionConfiguration
是准备好的。 - 自动注入了
RedisTemplate<Object, Object>
,xxxTemplate
。 - 自动注入了
StringRedisTemplate
,key,value都是String - 底层只要我们使用
StringRedisTemplate
、RedisTemplate
就可以操作Redis。
外网Redis环境搭建:
阿里云按量付费Redis,其中选择经典网络。
申请Redis的公网连接地址。
修改白名单,允许
0.0.0.0/0
访问。
70、数据访问-Redis操作与统计小实验
相关Redis配置:
1 | spring: |
测试Redis连接:
1 |
|
Redis Desktop Manager:可视化Redis管理软件。
URL统计拦截器:
1 |
|
注册URL统计拦截器:
1 |
|
Filter、Interceptor 几乎拥有相同的功能?
- Filter是Servlet定义的原生组件,它的好处是脱离Spring应用也能使用。
- Interceptor是Spring定义的接口,可以使用Spring的自动装配等功能。
调用Redis内的统计数据:
1 |
|
71、单元测试-JUnit5简介
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库
作为最新版本的JUnit框架,JUnit5与之前版本的JUnit框架有很大的不同。由三个不同子项目的几个不同模块组成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform: Junit Platform是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。
JUnit Jupiter: JUnit Jupiter提供了JUnit5的新的编程模型,是JUnit5新特性的核心。内部包含了一个测试引擎,用于在Junit Platform上运行。
JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,JUnit3.x的测试引擎。
注意:
SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖。如果需要兼容JUnit4需要自行引入(不能使用JUnit4的功能 @Test)
JUnit 5’s Vintage已经从
spring-boot-starter-test
从移除。如果需要继续兼容Junit4需要自行引入Vintage依赖:
1 | <dependency> |
- 使用添加JUnit 5,添加对应的starter:
1 | <dependency> |
- Spring的JUnit 5的基本单元测试模板(Spring的JUnit4的是
@SpringBootTest
+@RunWith(SpringRunner.class)
):
1 | import org.junit.jupiter.api.Assertions; |
Jupiter
英 [ˈdʒuːpɪtə(r)] 美 [ˈdʒuːpɪtər]
n. 木星(太阳系中最大的行星)
vintage
英 [ˈvɪntɪdʒ] 美 [ˈvɪntɪdʒ]
n. 特定年份(或地方)酿制的酒;酿造年份;采摘葡萄酿酒的期间(或季节);葡萄收获期(或季节)
adj. (指葡萄酒)优质的,上等的,佳酿的;古色古香的(指1917–1930年间制造,车型和品味受人青睐的);(过去某个时期)典型的,优质的;(某人的)最佳作品的
72、单元测试-常用测试注解
- @Test:表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
- @ParameterizedTest:表示方法是参数化测试。
- @RepeatedTest:表示方法可重复执行。
- @DisplayName:为测试类或者测试方法设置展示名称。
- @BeforeEach:表示在每个单元测试之前执行。
- @AfterEach:表示在每个单元测试之后执行。
- @BeforeAll:表示在所有单元测试之前执行。
- @AfterAll:表示在所有单元测试之后执行。
- @Tag:表示单元测试类别,类似于JUnit4中的@Categories。
- @Disabled:表示测试类或测试方法不执行,类似于JUnit4中的@Ignore。
- @Timeout:表示测试方法运行如果超过了指定时间将会返回错误。
- @ExtendWith:为测试类或测试方法提供扩展类引用。
1 | import org.junit.jupiter.api.*; |
73、单元测试-断言机制
断言Assertion是测试方法中的核心部分,用来对测试需要满足的条件进行验证。这些断言方法都是org.junit.jupiter.api.Assertions的静态方法。检查业务逻辑返回的数据是否合理。所有的测试运行结束以后,会有一个详细的测试报告。
JUnit 5 内置的断言可以分成如下几个类别:
简单断言
用来对单个值进行简单的验证。如:
方法 | 说明 |
---|---|
assertEquals | 判断两个对象或两个原始类型是否相等 |
assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
assertSame | 判断两个对象引用是否指向同一个对象 |
assertNotSame | 判断两个对象引用是否指向不同的对象 |
assertTrue | 判断给定的布尔值是否为 true |
assertFalse | 判断给定的布尔值是否为 false |
assertNull | 判断给定的对象引用是否为 null |
assertNotNull | 判断给定的对象引用是否不为 null |
1 |
|
数组断言
通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等。
1 |
|
组合断言
assertAll()
方法接受多个 org.junit.jupiter.api.Executable
函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言。
1 |
|
异常断言
在JUnit4时期,想要测试方法的异常情况时,需要用@Rule
注解的ExpectedException
变量还是比较麻烦的。而JUnit5提供了一种新的断言方式Assertions.assertThrows()
,配合函数式编程就可以进行使用。
1 |
|
超时断言
JUnit5还提供了Assertions.assertTimeout()为测试方法设置了超时时间。
1 |
|
快速失败
通过 fail 方法直接使得测试失败。
1 |
|
74、单元测试-前置条件
Unit 5 中的前置条件(assumptions【假设】)类似于断言,不同之处在于不满足的断言assertions会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。
前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。
1 |
|
assumeTrue
和 assumFalse
确保给定的条件为 true
或 false
,不满足条件会使得测试执行终止。
assumingThat
的参数是表示条件的布尔值和对应的 Executable 接口的实现对象。只有条件满足时,Executable
对象才会被执行;当条件不满足时,测试执行并不会终止。
75、单元测试-嵌套测试
JUnit 5 可以通过 Java 中的内部类和@Nested
注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach
和@AfterEach
注解,而且嵌套的层次没有限制。
1 |
|
76、单元测试-参数化测试
参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。
利用@ValueSource等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
利用**@ValueSource**等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
- @ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
- @NullSource: 表示为参数化测试提供一个null的入参
- @EnumSource: 表示为参数化测试提供一个枚举入参
- @CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
- @MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
当然如果参数化测试仅仅只能做到指定普通的入参还达不到让我觉得惊艳的地步。让我真正感到他的强大之处的地方在于他可以支持外部的各类入参。如:CSV,YML,JSON 文件甚至方法的返回值也可以作为入参。只需要去实现**ArgumentsProvider
**接口,任何外部文件都可以作为它的入参。
1 |
|
迁移指南
在进行迁移的时候需要注意如下的变化:
- 注解在
org.junit.jupiter.api
包中,断言在org.junit.jupiter.api.Assertions
类中,前置条件在org.junit.jupiter.api.Assumptions
类中。 - 把
@Before
和@After
替换成@BeforeEach
和@AfterEach
。 - 把
@BeforeClass
和@AfterClass
替换成@BeforeAll
和@AfterAll。 - 把
@Ignore
替换成@Disabled
。 - 把
@Category
替换成@Tag
。 - 把
@RunWith
、@Rule
和@ClassRule
替换成@ExtendWith
。
77、指标监控-SpringBoot Actuator与Endpoint
未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。
官方文档 - Spring Boot Actuator: Production-ready Features
1.x与2.x的不同:
SpringBoot Actuator 1.x
- 支持SpringMVC
- 基于继承方式进行扩展
- 层级Metrics配置
- 自定义Metrics收集
- 默认较少的安全策略
SpringBoot Actuator 2.x
- 支持SpringMVC、JAX-RS以及Webflux
- 注解驱动进行扩展
- 层级&名称空间Metrics
- 底层使用MicroMeter,强大、便捷默认丰富的安全策略
如何使用
- 添加依赖:
1 | <dependency> |
- 访问
http://localhost:8080/actuator/**
。 - 暴露所有监控信息为HTTP。
1 | management: |
- 测试例子
actuator
英 [ˈæktjʊeɪtə] 美 [ˈæktjuˌeɪtər]
n. 致动(促动,激励,调节)器;传动(装置,机构);拖动装置;马达;操作机构;执行机构(元件);(电磁铁)螺线管;操纵装置(阀门);调速控制器;往复运动油(气)缸;作动筒
metric
英 [ˈmetrɪk] 美 [ˈmetrɪk]
adj. 米制的;公制的;按公制制作的;用公制测量的
n. 度量标准;[数学]度量;诗体;韵文;诗韵
78、指标监控-常使用的端点及开启与禁用
常使用的端点
ID | 描述 |
---|---|
auditevents |
暴露当前应用程序的审核事件信息。需要一个AuditEventRepository组件 。 |
beans |
显示应用程序中所有Spring Bean的完整列表。 |
caches |
暴露可用的缓存。 |
conditions |
显示自动配置的所有条件信息,包括匹配或不匹配的原因。 |
configprops |
显示所有@ConfigurationProperties 。 |
env |
暴露Spring的属性ConfigurableEnvironment |
flyway |
显示已应用的所有Flyway数据库迁移。 需要一个或多个Flyway 组件。 |
health |
显示应用程序运行状况信息。 |
httptrace |
显示HTTP跟踪信息(默认情况下,最近100个HTTP请求-响应)。需要一个HttpTraceRepository 组件。 |
info |
显示应用程序信息。 |
integrationgraph |
显示Spring integrationgraph 。需要依赖spring-integration-core 。 |
loggers |
显示和修改应用程序中日志的配置。 |
liquibase |
显示已应用的所有Liquibase数据库迁移。需要一个或多个Liquibase 组件。 |
metrics |
显示当前应用程序的“指标”信息。 |
mappings |
显示所有@RequestMapping 路径列表。 |
scheduledtasks |
显示应用程序中的计划任务。 |
sessions |
允许从Spring Session支持的会话存储中检索和删除用户会话。需要使用Spring Session的基于Servlet的Web应用程序。 |
shutdown |
使应用程序正常关闭。默认禁用。 |
startup |
显示由ApplicationStartup 收集的启动步骤数据。需要使用SpringApplication 进行配置BufferingApplicationStartup 。 |
threaddump |
执行线程转储。 |
如果您的应用程序是Web应用程序(Spring MVC,Spring WebFlux或Jersey),则可以使用以下附加端点:
ID | 描述 |
---|---|
heapdump |
返回hprof 堆转储文件。 |
jolokia |
通过HTTP暴露JMX bean(需要引入Jolokia,不适用于WebFlux)。需要引入依赖jolokia-core 。 |
logfile |
返回日志文件的内容(如果已设置logging.file.name 或logging.file.path 属性)。支持使用HTTPRange 标头来检索部分日志文件的内容。 |
prometheus |
以Prometheus服务器可以抓取的格式公开指标。需要依赖micrometer-registry-prometheus 。 |
其中最常用的Endpoint:
- Health:监控状况
- Metrics:运行时指标
- Loggers:日志记录
Health Endpoint
健康检查端点,我们一般用于在云平台,平台会定时的检查应用的健康状况,我们就需要Health Endpoint可以为平台返回当前应用的一系列组件健康状况的集合。
重要的几点:
- health endpoint返回的结果,应该是一系列健康检查后的一个汇总报告。
- 很多的健康检查默认已经自动配置好了,比如:数据库、redis等。
- 可以很容易的添加自定义的健康检查机制。
Metrics Endpoint
提供详细的、层级的、空间指标信息,这些信息可以被pull(主动推送)或者push(被动获取)方式得到:
- 通过Metrics对接多种监控系统。
- 简化核心Metrics开发。
- 添加自定义Metrics或者扩展已有Metrics。
开启与禁用Endpoints
- 默认所有的Endpoint除过shutdown都是开启的。
- 需要开启或者禁用某个Endpoint。配置模式为
management.endpoint.<endpointName>.enabled = true
1 | management: |
- 或者禁用所有的Endpoint然后手动开启指定的Endpoint。
1 | management: |
暴露Endpoints
支持的暴露方式
- HTTP:默认只暴露health和info。
- JMX:默认暴露所有Endpoint。
- 除过health和info,剩下的Endpoint都应该进行保护访问。如果引入Spring Security,则会默认配置安全访问规则。
ID | JMX | Web |
---|---|---|
auditevents |
Yes | No |
beans |
Yes | No |
caches |
Yes | No |
conditions |
Yes | No |
configprops |
Yes | No |
env |
Yes | No |
flyway |
Yes | No |
health |
Yes | Yes |
heapdump |
N/A | No |
httptrace |
Yes | No |
info |
Yes | Yes |
integrationgraph |
Yes | No |
jolokia |
N/A | No |
logfile |
N/A | No |
loggers |
Yes | No |
liquibase |
Yes | No |
metrics |
Yes | No |
mappings |
Yes | No |
prometheus |
N/A | No |
scheduledtasks |
Yes | No |
sessions |
Yes | No |
shutdown |
Yes | No |
startup |
Yes | No |
threaddump |
Yes | No |
若要更改公开的Endpoint,请配置以下的包含和排除属性:
Property | Default |
---|---|
management.endpoints.jmx.exposure.exclude |
|
management.endpoints.jmx.exposure.include |
* |
management.endpoints.web.exposure.exclude |
|
management.endpoints.web.exposure.include |
info, health |
79、指标监控-定制Endpoint
定制 Health 信息
1 | management: |
通过实现HealthIndicator
接口,或继承MyComHealthIndicator
类。
1 | import org.springframework.boot.actuate.health.Health; |
1 |
|
定制info信息
常用两种方式:
- 编写配置文件
1 | info: |
- 编写InfoContributor
1 | import java.util.Collections; |
http://localhost:8080/actuator/info 会输出以上方式返回的所有info信息
定制Metrics信息
增加定制Metrics:
1 | class MyService{ |
1 | //也可以使用下面的方式 |
定制Endpoint
1 |
|
场景:
- 开发ReadinessEndpoint来管理程序是否就绪。
- 开发LivenessEndpoint来管理程序是否存活。
80、指标监控-Boot Admin Server
可视化指标监控
What is Spring Boot Admin?
codecentric’s Spring Boot Admin is a community project to manage and monitor your Spring Boot ® applications. The applications register with our Spring Boot Admin Client (via HTTP) or are discovered using Spring Cloud ® (e.g. Eureka, Consul). The UI is just a Vue.js application on top of the Spring Boot Actuator endpoints.
81、高级特性-Profile环境切换
为了方便多环境适配,Spring Boot简化了profile功能。
- 默认配置文件
application.yaml
任何时候都会加载。 - 指定环境配置文件
application-{env}.yaml
,env
通常替代为test
, - 激活指定环境
- 配置文件激活:
spring.profiles.active=prod
- 命令行激活:
java -jar xxx.jar --spring.profiles.active=prod --person.name=haha
(修改配置文件的任意值,命令行优先)
- 配置文件激活:
- 默认配置与环境配置同时生效
- 同名配置项,profile配置优先
@Profile条件装配功能
1 |
|
application.properties
1 | person: |
1 | public interface Person { |
application-test.yaml
1 | person: |
application-prod.yaml
1 | person: |
application.properties
1 | # 激活prod配置文件 |
1 |
|
@Profile还可以修饰在方法上:
1 | class Color { |
可以激活一组:
1 | spring.profiles.active=production |
82、高级特性-配置加载优先级
外部化配置
官方文档 - Externalized Configuration
Spring Boot uses a very particular PropertySource
order that is designed to allow sensible overriding of values. Properties are considered in the following order (with values from lower items overriding earlier ones)(1优先级最低,14优先级最高):
- Default properties (specified by setting
SpringApplication.setDefaultProperties
). @PropertySource
annotations on your@Configuration
classes. Please note that such property sources are not added to theEnvironment
until the application context is being refreshed. This is too late to configure certain properties such aslogging.*
andspring.main.*
which are read before refresh begins.- Config data (such as
application.properties
files) - A
RandomValuePropertySource
that has properties only inrandom.*
. - OS environment variables.
- Java System properties (
System.getProperties()
). - JNDI attributes from
java:comp/env
. ServletContext
init parameters.ServletConfig
init parameters.- Properties from
SPRING_APPLICATION_JSON
(inline JSON embedded in an environment variable or system property). - Command line arguments.
properties
attribute on your tests. Available on@SpringBootTest
and the test annotations for testing a particular slice of your application.@TestPropertySource
annotations on your tests.- Devtools global settings properties in the
$HOME/.config/spring-boot
directory when devtools is active.
1 | import org.springframework.stereotype.*; |
- 外部配置源
- Java属性文件。
- YAML文件。
- 环境变量。
- 命令行参数。
- 配置文件查找位置
- classpath 根路径。
- classpath 根路径下config目录。
- jar包当前目录。
- jar包当前目录的config目录。
- /config子目录的直接子目录。
- 配置文件加载顺序:
- 当前jar包内部的
application.properties
和application.yml
。 - 当前jar包内部的
application-{profile}.properties
和application-{profile}.yml
。 - 引用的外部jar包的
application.properties
和application.yml
。 - 引用的外部jar包的
application-{profile}.properties
和application-{profile}.yml
。
- 当前jar包内部的
- 指定环境优先,外部优先,后面的可以覆盖前面的同名配置项。
83、高级特性-自定义starter细节
starter启动原理
- starter的pom.xml引入autoconfigure依赖
1 | graph LR |
autoconfigure包中配置使用
META-INF/spring.factories
中EnableAutoConfiguration
的值,使得项目启动加载指定的自动配置类编写自动配置类
xxxAutoConfiguration
->xxxxProperties
@Configuration
@Conditional
@EnableConfigurationProperties
@Bean
- ……
引入starter —
xxxAutoConfiguration
— 容器中放入组件 —-绑定xxxProperties
—- 配置项
自定义starter
目标:创建
HelloService
的自定义starter。创建两个工程,分别命名为
hello-spring-boot-starter
(普通Maven工程),hello-spring-boot-starter-autoconfigure
(需用用到Spring Initializr创建的Maven工程)。hello-spring-boot-starter
无需编写什么代码,只需让该工程引入hello-spring-boot-starter-autoconfigure
依赖:
1 |
|
hello-spring-boot-starter-autoconfigure
的pom.xml如下:
1 |
|
- 创建4个文件:
com/lun/hello/auto/HelloServiceAutoConfiguration
com/lun/hello/bean/HelloProperties
com/lun/hello/service/HelloService
src/main/resources/META-INF/spring.factories
1 | import com.lun.hello.bean.HelloProperties; |
1 | import org.springframework.boot.context.properties.ConfigurationProperties; |
1 | import com.lun.hello.bean.HelloProperties; |
1 | # Auto Configure |
用maven插件,将两工程install到本地。
接下来,测试使用自定义starter,用Spring Initializr创建名为
hello-spring-boot-starter-test
工程,引入hello-spring-boot-starter
依赖,其pom.xml如下:
1 |
|
- 添加配置文件
application.properties
:
1 | hello.prefix=hello |
- 添加单元测试类:
1 | import com.lun.hello.service.HelloService;//来自自定义starter |
84、原理解析-SpringApplication创建初始化流程
SpringBoot启动过程
Spring Boot应用的启动类:
1 | import org.springframework.boot.SpringApplication; |
1 | public class SpringApplication { |
spring.factories:
1 | ... |
85、原理解析-SpringBoot完整启动过程
继续上一节,接着讨论return new SpringApplication(primarySources).run(args)
的run
方法
1 | public class SpringApplication { |
1 | //2. new SpringApplication(primarySources).run(args) 最后返回的接口类型 |
1 | #4. |
1 | class SpringApplicationRunListeners { |
86、原理解析-自定义事件监听组件
MyApplicationContextInitializer.java
1 | import org.springframework.context.ApplicationContextInitializer; |
MyApplicationListener.java
1 | import org.springframework.context.ApplicationEvent; |
MyApplicationRunner.java
1 | import org.springframework.boot.ApplicationArguments; |
MyCommandLineRunner.java
1 | import org.springframework.boot.CommandLineRunner; |
MySpringApplicationRunListener.java
1 | import org.springframework.boot.ConfigurableBootstrapContext; |
注册MyApplicationContextInitializer
,MyApplicationListener
,MySpringApplicationRunListener
:
resources / META-INF / spring.factories
:
1 | org.springframework.context.ApplicationContextInitializer=\ |
87、后会有期
路漫漫其修远兮,吾将上下而求索。
纸上得来终觉浅,绝知此事要躬行。
Spring Boot 2 场景整合篇
- 虚拟化技术
- 安全控制
- 缓存技术
- 消息中间件
- 对象存储
- 定时调度
- 异步任务
- 分布式系统
Spring Boot 2 响应式编程
- 响应式编程基础
- Webflux开发Web应用
- 响应式访问持久化层
- 响应式安全开发
- 响应式原理