今日授课目标
-
掌握工程热部署
-
掌握多环境的配置文件
-
掌握配置文件存放路径,及其加载顺序
-
掌握自定义配置文件名称
-
掌握内置web应用服务器的切换:tomcat切换为jetty
-
掌握为SpringBoot配置生产级监控Actuator
-
搭建Spring Boot Admin服务链接SpringBoot项目
-
了解SpringBoot自动配置实现原理【不要求掌握】
七、SpringBoot工程热部署
只需导入开发者工具依赖坐标,即可实现热部署功能:
<!--spring-boot开发工具jar包,支持热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
但还需注意:加入坐标之后,如果想要代码立即生效,必须在修改代码之后进行代码构建。默认情况IDEA不会自动构建,需要手动构建。如图两处地方均可。
每次手动构建很麻烦?!!还有一种自动构建解决方案,但不建议使用。就是设置Build Project Automatically
。同时打开Maintenance维护(打开快捷键Shift + Ctrl + Alt + /
),选择Registry(注册表),设置运行时自动编译。
八、配置文件延伸
8.1 多环境配置文件
我们在开发Spring Boot应用时,通常同一套程序会被安装到不同环境,比如:开发dev、测试test、生产pro等。其中数据库地址、服务器端口等等配置都不同,如果每次打包时,都要修改配置文件,那么非常麻烦。profile功能就是来进行动态配置切换的。
profile配置方式有两种:
-
多profile文件方式:提供多个配置文件,每个代表一种环境。
-
application-dev.properties/yml 开发环境
-
application-test.properties/yml 测试环境
-
application-pro.properties/yml 生产环境
-
-
yml多文档方式:在yml中使用 --- 分隔不同配置
profile激活方式:
-
配置文件: 再配置文件中配置:spring.profiles.active=dev
-
虚拟机参数:在VM options 指定:-Dspring.profiles.active=dev
-
命令行参数:java –jar xxx.jar --spring.profiles.active=dev
8.2 松散绑定
不论配置文件中的属性值是短横线、驼峰式还是下换线分隔配置方式,在注入配置时都可以通过短横线方式取出值;
使用范围:properties文件、YAML文件、系统属性
命名风格 | 示例 |
---|---|
短横线分隔 | hou.spring-boot.one-example |
驼峰式 | hou.SpringBoot.OneExample |
下划线分隔 | hou.spring_boot.one_example |
注意:@Value取值配置不能写驼峰式和下划线,只能写短横线,否则会报错
8.3 配置路径及其加载顺序
Springboot程序启动时,会从以下位置加载配置文件:
-
1.file:./config/:当前项目下的/config目录下
-
2.file:./ :当前项目的根目录
-
3.classpath:/config/:classpath的/config目录
-
4.classpath:/ :classpath的根目录
加载顺序为上文的排列顺序,高优先级配置的属性会生效
注意:在多个model的工程中,这种配置顺序不生效
8.5 修改配置文件的位置及默认名称:
第一种方式:IDEA通过参数注入方式配置:
第二种方式:命令行:
# 自定义配置文件名称 --spring.config.name=myApplication # 指定配置文件存储位置 --spring.config.location=classpath:/myconfig/application.yml
九、SpringBoot进阶
9.1 SpringBoot的监听器
1、什么是监听器
JavaEE包括13门规范,其中 Servlet规范包括三个技术点:Servlet、Listener、Filter
监听器就是监听某个对象的状态变化的组件
监听器,字面上的理解就是,观察监听某个事件的发生,当被监听的事件真的发生了,在这个事件发生后做点事
监听器的相关概念:
-
事件源:被监听的对象
-
监听器:监听事件源对象 事件源对象的状态的变化都会触发监听器
-
响应行为:监听器监听到事件源的状态变化时 所涉及的功能代码 ---- 程序员编写的代码
1、js中的事件监听机制:οnclick=fun()
2、Servlet中的监听器:web.xml
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
3、SpringBoot中的监听器
-
CommandLineRunner:应用程序启动完成后
-
ApplicationRunner:应用程序启动完成后
-
ApplicationContextInitializer:应用程序初始化之前【对框架开发者有意义】
-
SpringApplicationRunListener:应用程序全阶段监听【对框架开发者有意义】
-
应用程序开始启动--starting
-
环境准备完成--environmentPrepared
-
spring容器准备完成--environmentPrepared
-
spring容器加载完成--environmentPrepared
-
应用程序启动完成--started
-
应用程序开始运行--running
-
应用程序运行时抛出异常时调用--failed
-
Spring Boot的扩展机制Spring Factories
主要目的是解耦:将监听器的配置权交给第三方厂商、插件开发者
框架提供接口,实现类由你自己来写,释放原生API能力,增加可定制性
META-INF/spring.factories文件中配置接口的实现类名称
在ApplicationContextInitializer接口的实现类中必须写一个构造方法:
//注意:此构造方法必须要写 public My04SpringApplicationRunListener(SpringApplication application, String[] args) {}
2、监听器案例
需求:当应用程序启动完成时,初始化redis缓存。
实现步骤:
-
实现ApplicationRunner接口,重写run()方法
-
注入UserService接口实现类及RedisTemplate对象
-
将用户数据存入redis缓存
实现过程:
//1.实现ApplicationRunner接口,重写run()方法 @Component public class InitialzerRedisCacheListnener implements ApplicationRunner { //2.注入UserService接口实现类及RedisTemplate对象 @Autowired private UserService userService; @Autowired private RedisTemplate redisTemplate; @Override public void run(ApplicationArguments args) throws Exception { //3.将缓存数据存入redis String key = UserService.class.getName() + ".findAll()"; redisTemplate.boundValueOps(key).set(userService.findAll()); } }
9.2 自动配置实现原理详解
redisTemplate的bean怎么注入spring容器中的?
redisTemplate中的host和port怎么配置的?
1、@Import注解进阶
三种Jar包外导入类的方式:
-
直接导入
-
通过配置类导入
-
通过ImportSelector接口实现类导入
2、@Configuration注解进阶
配置类中的条件注解@Conditional及其衍生注解
-
class类条件
-
@ConditionalOnClass==存在类条件
-
@ConditionalOnMissingClass==不存在类条件
-
-
属性条件
-
@ConditionalOnProperty==属性条件,还可以为属性设置默认值
-
-
Bean条件
-
@ConditionalOnBean==存在Bean条件
-
@ConditionalOnMissingBean==不存在Bean条件
-
@ConditionalOnSingleCondidate==只有一个Bean条件
-
-
资源条件
-
@ConditionalResource==资源条件
-
-
Web应用条件
-
@ConditionalOnWebApplication==web应用程序条件
-
@ConditionalOnNotWebApplication==不是web应用程序条件
-
-
其他条件
-
@ConditionalOneExpression==EL表达式条件
-
@ConditionalOnJava==在特定的Java版本条件
-
自动配置类的执行顺序
-
@AutoConfigureBefore==在那些自动配置之前执行
-
@AutoConfigureAfter==在那些自动配置之后执行
-
@AutoConfigureOrder==自动配置顺序
Redis的自动配置
Mybatis的自动配置
3、@EnableAutoConfiguration注解
其本质是配置类@Import与@Configuration的组合
9.3 自定义auto-configuration及starter
目标:
为传智播客教育集团研究院开发的,基于自主研发的模板引擎代码生成神器加入自动配置。要求当导入starter坐标时,自动创建代码生成器框架的核心对象codeutil。
分析过程:
参考Mybatis实现的自动配置
自动配置和starter是针对已有框架进行的整合!
必备四角色:框架、自动配置模块、starter模块、开发者
-
定制自动配置必要内容
-
autoconfiguration模块,包含自动配置代码。自定义itcast-spring-boot-autoconfigure。
-
starter模块。自定义itcast-spring-boot-starter
-
-
自动配置命名方式
-
官方的Starters
-
spring-boot-starter-*
-
-
非官方的starters
-
*-spring-boot-starter
-
-
-
SpringBoot起步依赖,Starter Dependencies
一些注意事项
-
starter中仅添加必备依赖坐标
-
需要声明对spring-boot-autoconfigure的依赖
-
测试项目的包名不能与自定义starter和自动配置的包名相同
-
com.hou
-
cn.itcast
-
实现步骤:
-
获取准备好的框架--黑马架构师-代码生成器
-
创建 itcast-spring-boot-autoconfigure 模块
-
定义代码生成器核心对象的配置类信息
-
在META-INF/spring.factories扩展自动配置
-
-
创建 itcast-spring-boot-starter 模块
-
将自动配置模块及starter模块安装到本地仓库
-
测试模块springboot04-test-my-auto-configuration
-
引入自定义的 itcast-spring-boot-starter依赖坐标
-
测试核心代码生成器对象,是否自动配置成功了
-
实现过程:
-
获取准备好的框架--黑马架构师-代码生成器
-
CodeUtils:
/** * 代码生成器,程序执行入口 */ public class CodeUtils { public void generatorCode(){ //生成代码 System.out.println("-----------黑马架构师代码生成器执行--------"); } }
-
-
创建 itcast-spring-boot-autoconfigure 模块
-
HeimaConfiguration
@Configuration @ConditionalOnClass(CodeUtils.class) @Import(HeimaProperties.class) public class HeimaConfiguration { //配置黑马架构师的核心对象CodeUtils @Bean @ConditionalOnProperty(name = "spring.heima.enable",havingValue = "true",matchIfMissing = true) public CodeUtils codeUtil(){ return new CodeUtils(); } }
-
HeimaProperties
@ConfigurationProperties(prefix = "spring.heima") public class HeimaProperties { private String username; private String password; //getter setter toString }
-
META-INF/spring.factories
# 注册自定义自动配置 org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.itcast.config.HeimaConfiguration
-
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.11.RELEASE</version> </parent> <groupId>cn.itcast</groupId> <artifactId>itcast-spring-boot-autoconfigure</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <!--导入需要加入自定义自动配置的框架--> <dependency> <groupId>cn.itcast</groupId> <artifactId>itcast-codeutils</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
-
-
创建 itcast-spring-boot-starter 模块
-
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itcast</groupId> <artifactId>itcast-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--架构师-代码生成器的依赖--> <dependency> <groupId>com.hou</groupId> <artifactId>itcast-codeutil</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--框架的自动配置依赖--> <dependency> <groupId>com.itcast</groupId> <artifactId>itcast-spring-boot-autoconfigure</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
-
-
将自动配置模块及starter模块安装到本地仓库,执行maven的install命令
-
测试模块springboot04-test-my-auto-configuration
-
引入自定义的 itcast-spring-boot-starter依赖坐标
<!--导入架构师的起步依赖--> <dependency> <groupId>cn.itcast</groupId> <artifactId>itcast-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
-
测试核心代码生成器对象,是否自动配置成功了
-
9.4 切换内置的web应用服务器
前置条件,必须会使用Maven helper的插件,懂得依赖排除
SpringBoot的web环境中默认使用tomcat作为内置服务器,其实SpringBoot提供了另外2中内置服务器供我们选择,我们可以很方便的进行切换。
Jetty: Jetty 是一个开源的servlet容器,它为基于Java的web容器,例如JSP和servlet提供运行环境。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。
Undertow: 是红帽公司开发的一款基于 NIO 的高性能 Web 嵌入式服务器
操作过程:
-
在spring-boot-starter-web排除tomcat
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--排除tomcat的starter--> <exclusions> <exclusion> <artifactId>spring-boot-starter-tomcat</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency>
-
导入其他容器的starter
<!--导入jetty容器依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
-
配置之后的效果
9.5 SpringBoot启动流程分析
执行流程图:
源码分析:
SpringApplication类的构造方法
//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(); //设置应用的初始化器 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //设置应用的监听器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // this.mainApplicationClass = deduceMainApplicationClass(); }
SpringApplication类的run()方法
//SpringApplication类的run()方法 public ConfigurableApplicationContext run(String... args) { //创建计时器,记录SpringBoot启动耗时 StopWatch stopWatch = new StopWatch(); stopWatch.start();//开始计时 //创建Spring的IOC容器 ConfigurableApplicationContext context = null; //SpringBoot异常报告对象 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //获取所有监听器 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting();//执行监听器的starting方法 try { //创建应用参数对象 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //准备应用环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); //打印Banner内容 Banner printedBanner = printBanner(environment); //创建Spring容器 context = createApplicationContext(); //获取异常报告的的实例 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //准备Spring的容器 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新Spring的容器,将所有对象注入Spring容器 refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop();//停止计时 if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //执行所有监听器的started方法 listeners.started(context); //启动完成 callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //执行监听器的running方法 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } //启动完成返回Spring的容器 return context; }
10、生产级监控Actuator
10.1 Actuator简介
SpringBoot自带监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、配置属性、日志信息等。
使用步骤:
-
导入依赖坐标
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
访问监控地址: http://localhost:8080/actuator
10.2 监控应用endpoint
路径 | 描述 | 默认开启 |
---|---|---|
/beans | 显示容器的全部的Bean,以及它们的关系 | Y |
/env | 获取全部环境属性 | Y |
/env/{name} | 根据名称获取特定的环境属性值 | Y |
/health | 显示健康检查信息 | Y |
/info | 显示设置好的应用信息 | Y |
/mappings | 显示所有的@RequestMapping信息 | Y |
/metrics | 显示应用的度量信息 | Y |
/scheduledtasks | 显示任务调度信息 | Y |
/httptrace | 显示Http Trace信息 | Y |
/caches | 显示应用中的缓存 | Y |
/conditions | 显示配置条件的匹配情况 | Y |
/configprops | 显示@ConfigurationProperties的信息 | Y |
/loggers | 显示并更新日志配置 | Y |
/shutdown | 关闭应用程序 | N |
/threaddump | 执行ThreadDump | Y |
/headdump | 返回HeadDump文件,格式为HPROF | Y |
/prometheus | 返回可供Prometheus抓取的信息 | Y |
举例:
http://localhost:8080/actuator/beans
http://localhost:8080/actuator/mappings
10.3 配置
# 暴露所有的监控点 management.endpoints.web.exposure.include=* # 定义Actuator访问路径 management.endpoints.web.base-path=/act # 开启endpoint 关闭服务功能 management.endpoint.shutdown.enabled=true # 连接SpringBoot的admin spring.boot.admin.client.url=http://localhost:9000
10.4 通过Spring Boot Admin了解程序的运行状态
目的:为SpringBoot应用程序提供一套管理界面
主要功能:
-
集中展示应用程序Actuator相关的内容
-
变更通知
搭建服务端:
①创建 admin-server 模块
②导入依赖坐标 admin-starter-server
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.hou</groupId> <artifactId>springboot06-admin-server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot06-admin-server</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-boot-admin.version>2.1.5</spring-boot-admin.version> </properties> <dependencies> <!--导入spring boot admin 服务端的启动依赖坐标 注意:必须导入其依赖管理清单bom --> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-server</artifactId> </dependency> </dependencies> <!--spring boot admin的依赖管理清单--> <dependencyManagement> <dependencies> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-dependencies</artifactId> <version>${spring-boot-admin.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
③在引导类上启用监控功能@EnableAdminServer
@SpringBootApplication @EnableAdminServer public class Springboot06AdminServerApplication { public static void main(String[] args) { SpringApplication.run(Springboot06AdminServerApplication.class, args); } }
配置客户端:
①创建 admin-client 模块
②导入依赖坐标 admin-starter-client
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.hou</groupId> <artifactId>springboot06-actuator</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot06-actuator</name> <description>Demo project for Spring Boot</description> <dependencies> <!--spring boot admin 客户端依赖坐标--> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> </dependency> <!--SpringBoot的生产级监控 Actuator依赖坐标--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <!--spring boot admin的bom--> <dependencyManagement> <dependencies> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-dependencies</artifactId> <version>2.1.5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
③配置相关信息:server地址等
# 暴露所有的监控点 management.endpoints.web.exposure.include=* # 定义Actuator访问路径 management.endpoints.web.base-path=/act # 开启endpoint 关闭服务功能 management.endpoint.shutdown.enabled=true # 连接SpringBoot的admin spring.boot.admin.client.url=http://localhost:9000
④启动server和client服务,访问server
总结
-
掌握工程热部署
-
掌握多环境的配置文件
-
掌握配置文件存放路径,及其加载顺序
-
掌握自定义配置文件名称application.yml
-
了解SpringBoot自动配置实现原理【不要求掌握】
-
掌握内置web应用服务器的切换:tomcat切换为jetty
-
了解为SpringBoot配置生产级监控Actuator
-
搭建Spring Boot Admin服务链接SpringBoot项目