如果您想保持Spring Boot MVC的默认配置,并在此基础上添加一些自定义配置,比如拦截器、格式化器、视图控制器等,可以创建一个使用@Configuration
注解的配置类,并实现WebMvcConfigurer
接口。同时不需要标注@EnableWebMvc
注解。
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器逻辑
}
@Override
public void addFormatters(FormatterRegistry registry) {
// 添加格式化器逻辑
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 添加视图控制器逻辑
}
}
例子
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 在请求之前记录日志
System.out.println("请求开始:" + request.getRequestURI());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
// 请求处理完成后记录日志
System.out.println("请求结束:" + request.getRequestURI());
}
}
java.util.Date
类型。首先,创建一个格式化器类来完成日期的格式化/解析:public class DateFormatter implements Formatter<Date> {
@Override
public Date parse(String text, Locale locale) throws ParseException {
// 将文本解析为日期对象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", locale);
return dateFormat.parse(text);
}
@Override
public String print(Date date, Locale locale) {
// 将日期对象格式化为文本
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", locale);
return dateFormat.format(date);
}
}
@Controller
public class ViewController {
@GetMapping("/hello")
public String hello() {
return "hello"; // 返回视图模板名称
}
}
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
//拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggingInterceptor());
}
//格式化器
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new DateFormatter());
}
//视图控制器
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello").setViewName("hello");
}
}
如果您只需要自定义一些核心组件实例,比如RequestMappingHandlerMapping
、RequestMappingHandlerAdapter
或ExceptionHandlerExceptionResolver
,可以通过创建一个WebMvcRegistrations
组件并将其注册到Spring容器中实现。这样您可以自行创建和配置这些核心组件的实例,而不会影响其他默认配置。
@Configuration
public class Testconfig implements WebMvcRegistrations {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping(){
//重写自己的逻辑
return null;
}
@Override
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter(){
//重写自己的逻辑
return null;
}
@Override
public ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {
//重写自己的逻辑
return null;
}
}
需要注意的是,完全自定义Spring MVC可能需要更多的工作和理解框架的内部机制。在大多数情况下,使用Spring MVC的默认配置和特性已经足够满足绝大多数Web应用程序的需要。只有在特殊情况下才需要进行完全自定义。
用于启用Spring MVC的完整功能,但是使用它可能会覆盖Spring Boot的自动配置,因此请谨慎使用。如果您只需要部分自定义配置,通常不需要使用@EnableWebMvc
注解,而是仅实现WebMvcConfigurer
接口即可。
@Configuration
@EnableWebMvc//这个注解加上的话,会将springBoot的默认配置覆盖掉,全部使用你定义的规则
public class StaticConfig {
@Bean
//将WebMvcConfigurer放在容器中
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
WebMvcConfigurer.super.addResourceHandlers(registry);
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/a/")
//缓存最大时间 单位秒
.setCacheControl(CacheControl.maxAge(7200, TimeUnit.SECONDS));
}
};
}
}
/webjars/**
的所有路径 资源都在 classpath:/META-INF/resources/webjars/
/**
的所有路径 资源都在 classpath:/META-INF/resources/
、classpath:/resources/
、classpath:/static/
、classpath:/public/
#1、spring.web:
# 1.配置国际化的区域信息
# 2.静态资源策略(开启、处理链、缓存)
# 开启缓存映射
spring.web.resources.add-mappings=true
# 设置缓存间隔时间
spring.web.resources.cache.period=3600
# 缓存详细合并项控制,会覆盖.period这一项
spring.web.resources.cache.cachecontrol.max-age=7200
# 使用use-last-modified 服务器在接收到请求的时候,会给客户端返回一个时间
# 这个时间就是静态资源最后一次修改的时间,如果客户端当前时间和这个返回的时间相同的话
# 就说明这个资源没有被修改,客户端直接从缓存中获取,否则,将在服务器中重新获取这个静态资源
# 不设置,默认为开启,true
spring.web.resources.cache.use-last-modified=true
# 自定义静态资源文件夹的位置
spring.web.resources.static-locations=classpath:/a/
# 自定义静态资源规则
# 自定义webjars访问路径
spring.mvc.webjars-path-pattern=/wjs/**
# 自定静态资源访问路径
spring.mvc.static-path-pattern=/static/**
配置了访问路径.static-path-pattern
以后,在浏览器请求时,请求路径就要写http://localhost:8080/static/hyp.jpg
在配置了资源文件夹位置static-locations
后 静态资源的存放位置就变了
**注意:**只要将WebMvcConfigurer加入到容器中,配置的底层行为就会生效
加上@EnableMvc
注解就会禁用springBoot的默认配置
/**
* 使用代码方式配置静态资源规则,代替使用properties配置
* @author Han
* @data 2023/7/17
* @apiNode
*/
@Configuration
public class StaticConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//保留默认配置
WebMvcConfigurer.super.addResourceHandlers(registry);
//添加自己的配置【访问路径为/static/**】【修改静态资源所在包 为类路径下的a文件夹】
registry.addResourceHandler("/static/**")
//添加自己的配置【访问路径为/static/**】【修改静态资源所在包 为类路径下的a文件夹】
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/a/")
//缓存最大时间 单位秒
.setCacheControl(CacheControl.maxAge(7200, TimeUnit.SECONDS));
}
}
另一种方式,不继承WebMvcConfigurer类,将WebMvcConfigurer类作为一个Bean注册到容器中
@Configuration
@EnableWebMvc
public class StaticConfig {
@Bean
//将WebMvcConfigurer放在容器中
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
WebMvcConfigurer.super.addResourceHandlers(registry);
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/a/")
//缓存最大时间 单位秒
.setCacheControl(CacheControl.maxAge(7200, TimeUnit.SECONDS));
}
};
}
}
欢迎页规则在 WebMvcAutoConfiguration 中进行了定义:
favicon.ico
favicon.ico
,就可以改变网页的图标@GetMapping("/testPath/a*/b?/{pp}/**")
public String testPath(@PathVariable("pp") String pp, HttpServletRequest request){
var requestURL = request.getRequestURL();
System.out.println(requestURL);
return requestURL.toString()+"参数pp="+pp;
}
**
放在路径的中间位置,@GetMapping("/testPath/**/a*/b?/{pp}/**")
@GetMapping("/testPath/**/a*/b?/{pp}/**")
public String testPath(@PathVariable("pp") String pp, HttpServletRequest request){
var requestURL = request.getRequestURL();
System.out.println(requestURL);
return requestURL.toString()+"参数pp="+pp;
}
解决方法就是将路径匹配规则在配置文件中修改为spring.mvc.pathmatch.matching-strategy=ant_path_matcher
这是因为新版springBoot默认支持的路径匹配风格是spring.mvc.pathmatch.matching-strategy=path_pattern_parser
这个效率非常高但是不支持将**写在路径的中间位置
修改配置文件后:
一套系统支持返回多种数据类型
分为:
控制器方法
/**
* 测试内容协商
* 1、返回结果为json
* 这里遇到了问题,网页无法显示json数据
* 是因为当时没有给pojo类中提供get方法,提供以后正常了
* @return
*/
@GetMapping("/person")
public Person person(){
return new Person("小韩", 21);
}
因为springBoot化境下默认导入了json类型的内容协商,所以返回一个对象在浏览器默认显示的是Json
导入支持转换成xml格式的依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformatgroupId>
<artifactId>jackson-dataformat-xmlartifactId>
dependency>
给要返回的数据的类上标注@
注解
@JacksonXmlRootElement//可以写出为xml文档
public class Person {
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
…………
配置配置文件
注意:基于请求头的内容协商是默认开启的,但是基于请求参数的是需要手动开启的
# 开启基于请求参数的内容协商
spring.mvc.contentnegotiation.favor-parameter=true
# 修改请求参数指定内容协商时的使用的参数名 默认为format
spring.mvc.contentnegotiation.parameter-name=type
1、增加媒体类型支持的依赖
2、编写properties媒体类型配置
3、编写自己的MessageConverter
4、编写HttpMessageConverter。也就是在配置类中配置MessageConverter,将编写的MessageConverter添加到底层
八个:
ByteArrayHttpMessageConverter
: 支持字节数据读写StringHttpMessageConverter
: 支持字符串读写ResourceHttpMessageConverter
:支持资源读写ResourceRegionHttpMessageConverter
: 支持分区资源写出AllEncompassingFormHttpMessageConverter
:支持表单xml/json读写MappingJackson2HttpMessageConverter
: 支持请求响应体Json读写系统提供默认的MessageConverter 功能有限,仅用于json或者普通返回数据。额外增加新的内容协商功能,必须增加新的
HttpMessageConverter
1、添加依赖
添加支持返回yaml格式的依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformatgroupId>
<artifactId>jackson-dataformat-yamlartifactId>
dependency>
2、编写配置
# 增加yaml类型 spring.mvc.contentnegotiation.media-types.yaml=text/yaml
3、编写组件 自己的MessageConverter
作用是将对象转换成yaml格式写出【这一步可以将对象自己定义返回类型】
/**
* 编写组件
* 将对象可以返回为yaml格式
* @author Han
* @data 2023/7/22
* @apiNode
*/
//编写自己的类,继承AbstractHttpMessageConverter类
public class MyYamlHttpConverters extends AbstractHttpMessageConverter<Object> {
private ObjectMapper objectMapper;
public MyYamlHttpConverters() {
//定义媒体类型,这里的类型要和配置文件中一致
super(new MediaType("text", "yaml", Charset.forName("utf-8")));
YAMLFactory disableYaml = new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);
//转xml或者Yaml都是ObjectMapper来起作用的
this.objectMapper = new ObjectMapper(disableYaml);
}
@Override
protected boolean supports(Class<?> clazz) {
//这里可以添加逻辑判断
// 判断传入的否是一个对象
//在这里先不判断
return true;
}
@Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override//将对象写出去
protected void writeInternal(Object methodReturnValue, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
//获取对应的输出流
OutputStream body = outputMessage.getBody();
try {
this.objectMapper.writeValue(body, methodReturnValue);
} finally {
body.close();
}
}
}
4、在配置类中配置,增加HttpMessageConverter
在配置类中添加组件
@Configuration
public class StaticConfig {
@Bean
//将WebMvcConfigurer放在容器中
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
WebMvcConfigurer.super.addResourceHandlers(registry);
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/a/")
//缓存最大时间 单位秒
.setCacheControl(CacheControl.maxAge(7200, TimeUnit.SECONDS));
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MyYamlHttpConverters());
}
};
}
}
引入thymeleaf依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
自动配置原理
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration
自动配置ThymeleafProperties
中,对应配置文件spring.thymeleaf
内容classpath:/templates
文件夹下classpath:/templates/
下面找.html
的页面以用户登录为例子
使用步骤
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
/**
* 目标方法执行之前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("preHandle拦截的请求路径是{}", requestURI);
//登录检查逻辑
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if (loginUser != null) {
//放行
return true;
}
//拦截住。未登录。跳转到登录页
request.setAttribute("msg", "请先登录");
// re.sendRedirect("/");
request.getRequestDispatcher("/").forward(request, response);
return false;
}
/**
* 目标方法执行完成以后
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle执行{}", modelAndView);
}
/**
* 页面渲染以后
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse
response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion执行异常{}", ex);
}
}
2.拦截器注册到容器中(实现 WebMvcConfigurer 的 addInterceptors() )
3.指定拦截规则(注意,如果是拦截所有,静态资源也会被拦截】
@Configuration
public class AdminWebConfig implements WebMvcConfigurer{
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())//拦截器注册到容器中
.addPathPatterns("/**") //所有请求都被拦截包括静态资源
//放行的请求
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**", "/js/**","/aa/**");
}
在springBoot核心配置文件中进行配置时使用的是 spring.messages
编写国际化配置文件
默认:
配置文件名:message.properties
无区域代码
login=login
sign_in=sign_in
英文版:使用区域代码_en_US
配置文件名:message_en_US.properties
_en_US前的名称随意取
login=login
sign_in=sign_in
中文版:使用区域代码_zh_CN
配置文件名:message_zh_CN.properties
_zh_CN前的名称随意取
login=登录
sign_in=注册
使用thymeleaf语法进行国际化内容显示
使用#{}
[原理][https://www.yuque.com/leifengyang/springboot3/wp5l9qbu1k64frz1#mMAt4]可查看语雀文档的错误处理章节
1.前后端分离项目
前后端分离项目可使用@ControllerAdvice
+@ExceptionHandler
进行统一异常处理
2.服务端页面渲染【前后端不分离】
HTTP状态错误
给classpath:/templetes/error
目录下放精确码html
页面【404.html/500.html……】
给classpath:/templetes/error
目录下放模糊码html
页面【4xx.html/5xx.html……】
发生业务错误
核心业务**,每一种错误,都应该代码控制,跳转到自己定制的错误页。
通用业务**,classpath:/templates/error.html
页面,显示错误信息
注意: springBoot自动将错误信息封装到Modal中,如果要打印错误信息只需要在页面中直接使用${}
获取
前后端不分离方式
最后出现什么错误就会到对应的错误页面去显示错误信息
400.html:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
请求参数错误
<br>
错误信息:[[${message}]]
body>
html>
控制器方法
@Controller
@Slf4j
public class HtmlController {
@GetMapping("/hello")
public String hello(@RequestParam("name") String name , Model model){
//log.info(name);
//使用model向前端页面展示数据
model.addAttribute("name", name);
return "hello";
}
}
前后端分离方式
只需要集中处理错误,页面由前端负责
返回json数据,在页面的错误信息中显示json数据
/**
* @ControllerAdvice 这个注解表明这个类集中处理所有controller发生的错误
* @author Han
* @data 2023/7/26
* @apiNode
*/
@RestControllerAdvice
public class AllExceptionHandler {
@ExceptionHandler(Exception.class)//传入发生异常的类型
@ResponseBody
/**
* 写错误信息处理方法 可返回对象
* 发生什么错误返回什么对象
*/
public String handlerException(Exception e) {
return "错误!! 原因:"+e.getMessage();
}
}
starter
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>3.0.2version>
dependency>
<dependency>
<groupId>com.mysqlgroupId>
<artifactId>mysql-connector-jartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starter-testartifactId>
<version>3.0.2version>
<scope>testscope>
dependency>
dependencies>
# 配置数据源
# 驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# url
spring.datasource.url=jdbc:mysql://localhost:3306/p_springBoot
# 数据库用户名及密码
spring.datasource.username=root
spring.datasource.password=hyp
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
@Data
public class User {
private Long id;
private String loginName;
private String nickName;
private String passwd;
}
编写相关Mapper接口和Mapper.xml映射文件
@Mapper//标记@Mapper注解表明这个接口是一个Mapper
public interface UserMapper {
User getUserByID(@Param("id") Long id);
}
编写SQL映射文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hyp.ssm.mapper.UserMapper">
<select id="getUserByID" resultType="user">
select * from t_user where id = #{id}
select>
mapper>
编写controller控制器方法
@RestController
@Slf4j
public class UserController {
// 将Mapper接口注入
@Autowired
UserMapper userMapper;
@GetMapping("/getUserById/{id}")
public User getUserById(@PathVariable("id") Long id) {
log.info("查询id为【{}】的用户",id);
return userMapper.getUserByID(id);
}
}
mybatis相关配置
# 配置mybatis
# 别名机制 在Sql映射文件UserMapper.xml文件中的resultType属性使用别名
mybatis.type-aliases-package=com.hyp.ssm.bean
# 告诉mybatis SQL映射文件在哪里
mybatis.mapper-locations=classpath:/mapper/*.xml
# 开启驼峰命名映射
mybatis.configuration.map-underscore-to-camel-case=true
测试:
注意:
在标注Mapper接口时有两种方法
@Mapper
注解,加了这个注解后,明示了这个接口是一个Mapper接口,并且还将它作为一个bean交给ioc容器进行管理@MapperScan(basePackages = "填写Mapper接口所在包")
/**
*@MapperScan 这个注解是用来扫描Mapper接口的
* 如果在Mapper接口上添加了@Mapper注解,就不用再加这个注解了
*/
@SpringBootApplication
@MapperScan(basePackages = "com.hyp.ssm.mapper")
public class SsmApplication {
public static void main(String[] args) {
SpringApplication.run(SsmApplication.class, args);
}
}
@Profile
标记】@Profile({"test"})
@Component
public class Cat {
private Integer id;
private String name;
}
@Profile({"prod"})
@Component
public class Person {
private String name;
private Integer age;
private User user;
private Cat cat;
private Map<String, Dog> dogMap;
private List<Dog> dogs;
在配置文件中选择激活的环境进行激活
# 激活prod环境
spring.profiles.active=prod
生效的环境 = 激活的环境/默认环境 + 包含的环境
项目里面这么用
mybatis
、log
、xxx
:写到包含环境中db
、redis
:写到激活的环境中# 包含环境
# 不管是否激活了Dev 和 test 环境 总是要生效的环境
spring.profiles.include=prod,test
# 环境分组
spring.profiles.group.must=dev,test
spring.profiles.group.A = prod,test
# 可以选择一个组来激活
spring.profiles.active=must
dev(开发) text(测试) prod(生产)
【在组件类上添加@profile注解】
@Profile({"prod"})
……@Profile
那么就是所有环境下都能使用这个组件@Profile({"default"})
在没有激活指定环境时,默认只有这一个组件3、只有激活这些指定的环境,这些组件才能生效
2、激活环境
spring.profiles.active=prod
二:配置文件环境隔离
2、其他profile环境下配置文件命名规范:
`application-dev.properties`
application-test.properties
…… …… ……
格式:`application-{profile标识}.properties`
3、激活指定环境即可 会自动选择对应环境的配置文件进行配置
4、**项目的所有生效配置=激活的配置文件的所有项+主配置文件和激活文件`不冲突`的所有项**
* 如果发生了配置冲突 以激活的配置文件的配置为准
* 如:
* 在`application.properties`中配置的端口号为`8080`
* 在`application-dev.properties`中配置的端口号为`9090`
* 我们激活了`dev环境`,那么会以dev环境中的端口号`9090为准`
注意:要激活某个环境,只能在主配置文件中设置
application-{profile}.properties
可以作为指定环境的配置文件。
激活这个环境,配置就会生效。最终生效的所有配置是
application.properties
:主配置文件,任意时候都生效application-{profile}.properties
:指定环境配置文件,激活指定环境生效profile优先级 > application
常用的有:
注意:
配置文件优先级如下**(返序)**
application.properties/yml
application-{profile}.properties/yml
application.properties/yml
application-{profile}.properties/yml
# 导入一个配置文件,这配置文件中配置了server.port=9999
spring.config.import=classpath:aaa.properties
# 然后这里也设置了端口,但是因为是导入的配置,
# 所以优先级大于本身所有的,则最终端口是aaa.properties所定义的
server.port=8080
# 属性占位符,可以获取配置文件中的配置项的值
# 在controller中使用@value注解拿出来
portValue = 端口号是:${server.port}
@RestController
public class HelloController {
@Value("${portValue}")
String portValue;
@GetMapping("/getPort")
public String getPortValue(){
return portValue;
}
}
最终页面上显示:端口号是9999
package com.example.texing.CoreTeXing.listener;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import java.time.Duration;
/**
*
*
* Listener先要从 META-INF/spring.factories 读到
*
* 1、引导: 利用 BootstrapContext 引导整个项目启动
* starting: 应用开始,SpringApplication的run方法一调用,只要有了 BootstrapContext 就执行
* environmentPrepared: 环境准备好(把启动参数等绑定到环境变量中),但是ioc还没有创建;【调一次】
* 2、启动:
* contextPrepared: ioc容器创建并准备好,但是sources(主配置类)没加载。并关闭引导上下文;组件都没创建 【调一次】
* contextLoaded: ioc容器加载。主配置类加载进去了。但是ioc容器还没刷新(我们的bean没创建)。
* =======截止以前,ioc容器里面还没造bean呢=======
* started: ioc容器刷新了(所有bean造好了),但是 runner 没调用。
* ready: ioc容器刷新了(所有bean造好了),所有 runner 调用完了。
* 3、运行
* 以前步骤都正确执行,代表容器running。
* 4、运行失败
* failed 以上任意一个步骤如果发生了异常,就会启动失败
*
*/
public class MyListener implements SpringApplicationRunListener {
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("===starting=== 正在启动 ");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("===environmentPrepared=== 环境准备完成 ");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("===contextPrepared=== ioc容器准备完成 ");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("===contextLoaded=== ioc容器加载完成 ");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("===started=== 启动完成 ");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("===ready=== 准备就绪 ");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("===failed=== 应用启动失败 ");
}
}