下面就从运维实用篇开始讲,在运维实用篇中,我给学习者的定位是玩转配置
,为开发实用篇中做各种技术的整合做好准备工作。
主要分为以下内容:
下面开启第一部分SpringBoot程序打包与运行的学习
打包适合做完工程之后,将项目跑在服务器上
那我们的程序如何放置在这台专用的电脑上呢,这就要将我们的程序先组织成一个文件,然后将这个文件传输到这台服务器上。这里面就存在两个过程,一个是打包的过程,另一个是运行的过程。
一般流程:
打包指将程序转换成一个可执行的文件,所谓运行指不依赖开发环境执行打包产生的文件。
SpringBoot程序是基于Maven创建的,在Maven中提供有打包的指令,叫做package。本操作可以在Idea环境下执行。
mvn package
打包后会产生一个与工程名类似的jar文件,其名称是由模块名+版本号+.jar组成的。
程序包打好以后,就可以直接执行了。在程序包所在路径下,执行指令。
java -jar 工程包名.jar
执行程序打包指令后,程序正常运行,与在Idea下执行程序没有区别。
特别关注:在使用向导创建SpringBoot工程时,pom.xml文件中会有如下配置插件,这一段配置是专门为spring boot工程配置的,不能删除,否则无法运行jar包
org.springframework.boot
spring-boot-maven-plugin
总结
.jar文件工作机制
搞java开发平时会接触很多jar包,比如mysql的驱动jar包,而上面我们打包程序后得到的也是一个jar文件。这个时候如果你使用上面的java -jar指令去执行mysql的驱动jar包就会出现上述不可执行的现象。(因为MySQL的jar包中没有主启动类,MySQL的java文件要交给外部使用者去调用)
而我们的SpringBoot项目为什么能执行呢?其实是因为打包方式不一样。
在SpringBoot工程的pom.xml中有下面这组配置,这组配置决定了打包出来的程序包是否可以执行。
org.springframework.boot
spring-boot-maven-plugin
spring boot用maven插件打包目录结构
下面详细解释META-INF和org包含义
META-INF
包
包含pom.xml文件和MANIFEST.MF项目启动配置信息
spring boot工程用maven插件打包后的MANIFEST.MF
Manifest-Version: 1.0
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Implementation-Title: springboot_08_ssmp
Implementation-Version: 0.0.1-SNAPSHOT
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
//指明了boot工程的引导类
Start-Class: com.example.SSMPApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.6.11
Created-By: Maven JAR Plugin 3.2.2
//指明了boot工程启动时调用的主类
Main-Class: org.springframework.boot.loader.JarLauncher
org
包
这个包里面主要包含了Main-Class:JarLauncher.class
这组配置的工作流程
就是说java -jar命令后不会直接去启动引导类,而是会去先启动类JarLauncher
,再去启动引导类
总结
看来SpringBoot打出来了包为了能够独立运行,将所有需要使用的资源全部都添加到了这个lib包里。这就是为什么这个jar包能独立运行的原因。
总结
各位小伙伴在DOS环境下启动SpringBoot工程时,可能会遇到端口占用的问题。给大家一组命令,不用深入学习,备用吧。
# 查询端口
netstat -ano
# 查询指定端口
netstat -ano |findstr "端口号"
# 根据进程PID查询进程名称
tasklist |findstr "进程PID号"
# 根据PID杀死任务
taskkill /F /PID "进程PID号"
# 根据进程名称杀死任务
taskkill -f -t -im "进程名称"
临时属性添加位置:
目前我们的程序包打好了,可以发布了。但是程序包打好以后,里面的配置都已经是固定的了,比如配置了服务器的端口是8080。如果我要启动项目,发现当前我的服务器上已经有应用启动起来并且占用了8080端口,这个时候就尴尬了。难道要重新把打包好的程序修改一下吗?比如我要把打包好的程序启动端口改成80。
SpringBoot提供了灵活的配置方式,如果你发现你的项目中有个别属性需要重新配置,可以使用临时属性的方式快速修改某些配置。方法也特别简单,在启动的时候添加上对应参数就可以了。
java –jar springboot.jar –-server.port=80
当属性存在多级名称时,中间使用点分隔,和properties文件中的属性格式完全相同。
java –jar springboot.jar –-server.port=80 --logging.level.root=debug
- 常见优先级大小:临时属性 > 系统属性 > 配置文件
- 属性加载冲突分析
1. 优先级大小
现在我们的程序配置受两个地方控制了,第一配置文件,第二临时属性。并且我们发现临时属性的加载优先级要高于配置文件的。
第11条Command line arguments说的就是使用命令行临时参数。而这14种配置的顺序就是SpringBoot加载配置的顺序
属性读取冲突情况:
分析:当出现属性冲突的时候,可按那张图从下向上排查得出结果
在yaml中配置了user.name属性值,然后读取出来的时候居然不是自己的配置值,因为在系统属性中有一个属性叫做user.name,两个相互冲突了。而系统属性的加载优先顺序在上面这个列表中是5号,高于3号,所以SpringBoot最终会加载系统配置属性user.name。
总结
在idea中配置参数列表
做到这里其实可以产生一个思考了,如果对java编程熟悉的小伙伴应该知道,我们运行main方法的时候,如果想使用main方法的参数,也就是下面的args参数,就是在上面这个位置添加的参数。
public static void main(String[] args) {
}
原来是这样,通过这个args就可以获取到参数。再来看我们的引导类是如何书写的
public static void main(String[] args) {
SpringApplication.run(SSMPApplication.class,args);
}
这个args参数居然传递给了run方法,看来在Idea中配置的临时参数就是通过这个位置传递到我们的程序中的。言外之意,这里如果不用这个args是不是就断开了外部传递临时属性的入口呢?是这样的,我们可以使用下面的调用方式,这样外部临时属性就无法进入到SpringBoot程序中了。
public static void main(String[] args) {
SpringApplication.run(SSMPApplication.class);
}
或者还可以使用如下格式来玩这个操作,就是将配置不写在配置文件中,直接写成一个字符串数组,传递给程序入口。当然,这种做法并没有什么实际开发意义。
public static void main(String[] args) {
String[] arg = new String[1];
arg[0] = "--server.port=8082";
SpringApplication.run(SSMPApplication.class, arg);
}
总结
将多个配置属性放在一份文件里
- 文件优先级覆盖
- file :config/application.yml 【最高】(包路径下,与jar包的同层目录下)
- file :application.yml
- classpath:config/application.yml (类路径下)
- classpath:application.yml 【最低】
- 配置文件设置优先级的必要性:
在开发第一阶段用最低的配置级别,在开发第二阶段上线服务器后还需要改配置,这时就用第二级别的配置文件以此类推。
**级别1和2什么时候使用呢?**程序打包以后就要用这个级别了,管你程序里面配置写的是什么?我的级别高,可以轻松覆盖你,就不用考虑这些配置冲突的问题了。
总结
配置文件分为4种
多层级配置文件间的属性采用叠加并覆盖的形式作用于程序
自定义配置文件名字
之前咱们做配置使用的配置文件都是application.yml,其实这个文件也是可以改名字的,这样方便维护。比如我2020年4月1日搞活动,走了一组配置,2020年5月1日活动取消,恢复原始配置,这个时候只需要重新更换一下配置文件就可以了。但是你总不能在原始配置文件上修改吧,不然搞完活动以后,活动的配置就留不下来了,不利于维护。
自定义配置文件方式有如下两种:
方式一:使用临时属性设置配置文件名,注意仅仅是名称,不要带扩展名
方式二:使用临时属性设置配置文件路径,这个是全路径名
也可以设置加载多个配置文件
使用的属性一个是spring.config.name
,另一个是spring.config.location
,这个一定要区别清楚。
温馨提示
我们现在研究的都是SpringBoot单体项目,就是单服务器版本。其实企业开发现在更多的是使用基于SpringCloud技术的多服务器项目。这种配置方式和我们现在学习的完全不一样,所有的服务器将不再设置自己的配置文件,而是通过配置中心获取配置,动态加载配置信息。为什么这样做?集中管理。
总结
不同环境配置要分开写在不同的配置文件中,便于区分
例如MySQL配置要单独写在一个文件中,然后交给统一的环境管理
讲的内容距离线上开发越来越近了,下面说一说多环境开发问题。
什么是多环境?其实就是说你的电脑上写的程序最终要放到别人的服务器上去运行。每个计算机环境不一样,这就是多环境。常见的多环境开发主要兼顾3种环境设置,开发环境——自己用的,测试环境——自己公司用的,生产环境——甲方爸爸用的。因为这是绝对不同的三台电脑,所以环境肯定有所不同,比如连接的数据库不一样,设置的访问端口不一样等等。
那什么是多环境开发?就是针对不同的环境设置不同的配置属性即可。比如你自己开发时,配置你的端口如下:
server:
port: 80
如何想设计几组环境呢?中间使用三个减号分隔开
server:
port: 80
---
server:
port: 81
那用哪一个呢?设置默认启动哪个就可以了
spring:
config:
activate:
on-profile: pro #启动pro
---
spring:
profiles: pro
server:
port: 80
---
spring:
profiles: dev
server:
port: 81
---
spring:
profiles: test
server:
port: 82
总结
将原先在一个文件配置的不同环境,分成不同的配置文件
主配置文件中写共有的配置,并指明开发环境
分配置文件中指明不同开发环境下需要的配置
主配置文件
spring:
profiles:
active: pro # 启动pro
环境配置文件
server:
port: 80
环境配置文件因为每一个都是配置自己的项,所以连名字都不用写里面了。那问题是如何区分这是哪一组配置呢?使用文件名区分。
application-pro.yaml
server:
port: 80
application-dev.yaml
server:
port: 81
文件的命名规则为:application-环境名
.yml。
配置原则:在配置文件中,如果某些配置项所有环境都一样,可以将这些项写入到主配置中,只有哪些有区别的项才写入到环境配置文件中。
总结
可以使用独立配置文件定义环境属性
独立配置文件便于线上系统维护更新并保障系统安全性
SpringBoot最早期提供的配置文件格式是properties格式的,这种格式的多环境配置也了解一下吧。
主配置文件
spring.profiles.active=pro
环境配置文件
application-pro.properties
server.port=80
application-dev.properties
server.port=81
文件的命名规则为:application-环境名.properties。
总结
多文件
格式
解决问题:加载同一环境下不同的配置文件,将不同的配置文件合在一起
优先使用
group
语法开发冲突处理:
当主环境dev与其他环境有相同属性时,主环境属性生效(主环境配置优先);其他环境中有相同属性时,最后加载的环境属性生效
准备工作
将所有的配置根据功能对配置文件中的信息进行拆分,并制作成独立的配置文件,命名规则如下
使用
使用include属性在激活指定环境的情况下,同时对多个环境进行加载使其生效,多个环境间使用逗号分隔
spring:
profiles:
active: dev #相当于前缀
include: devDB,devRedis,devMVC #相当于后缀
比较一下,现在相当于加载dev配置时,再加载对应的3组配置,从结构上就很清晰,用了什么,对应的名称是什么
改良
SpringBoot从2.4版
开始使用group属性替代include属性,降低了配置书写量。简单说就是我先写好,你爱用哪个用哪个。
spring:
profiles:
active: dev
group:
"dev": devDB,devRedis,devMVC #用group分开管理环境
"pro": proDB,proRedis,proMVC
"test": testDB,testRedis,testMVC
现在再来看,如果切换dev到pro,只需要改一下是不是就结束了?完美!
出现意义:
Maven是管理多环境的,boot是做开发的,所以我最终用什么配置环境(application.yml),我要听Maven的设置,因此有必要在Maven中配置我要启动哪一个环境,然后boot开发文件中直接引用就行
说白了就是用maven来管理生产环境
配置步骤:
①在pom.xml文件中配置profile标签
②在pom.xml文件中的build标签下配置resources标签
多环境开发到这里基本上说完了,最后说一个冲突问题。就是maven和SpringBoot同时设置多环境的话怎么搞。
要想处理这个冲突问题,你要先理清一个关系,究竟谁在多环境开发中其主导地位。也就是说如果现在都设置了多环境,谁的应该是保留下来的,另一个应该遵从相同的设置。
maven是做什么的?项目构建管理的,最终生成代码包的,SpringBoot是干什么的?简化开发的。简化,又不是其主导作用。**最终还是要靠maven来管理整个工程,所以SpringBoot应该听maven的。**整个确认后下面就好做了。大体思想如下:
maven中设置多环境(使用属性方式区分环境)
<profiles>
<profile>
<id>env_devid>
<properties>
<profile.active>devprofile.active>
properties>
<activation>
<activeByDefault>trueactiveByDefault>
activation>
profile>
<profile>
<id>env_proid>
<properties>
<profile.active>proprofile.active>
properties>
profile>
profiles>
SpringBoot中读取maven设置值
spring:
profiles:
active: @profile.active@
上面的@属性名@就是读取maven中配置的属性值的语法格式。
需要在pom.xml中的build标签下添加,才能生效
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<filtering>truefiltering>
resource>
resources>
总结
日志的主要作用:
日志输出级别
日志输出级别控制:
步骤①:添加日志记录操作
@RestController
@RequestMapping("/books")
public class BookController extends BaseClass{
private static final Logger log = LoggerFactory.getLogger(BookController.class);
@GetMapping
public String getById(){
log.debug("debug...");
log.info("info...");
log.warn("warn...");
log.error("error...");
return "springboot is running...2";
}
}
上述代码中log对象就是用来记录日志的对象
步骤②:设置日志输出级别⭐️
日志设置好以后可以根据设置选择哪些参与记录。这里是根据日志的级别来设置的。日志的级别分为6种,分别是:
一般情况下,开发时候使用DEBUG,上线后使用INFO,运维信息记录使用WARN即可。下面就设置一下日志级别:
日志系统通常都提供了细粒度的控制来设置日志级别
# 开启debug模式,输出调试信息,常用于检查系统运行状况
debug: true
logging:
level:
root: debug
还可以再设置更细粒度的控制
步骤③:设置日志组,控制指定包对应的日志输出级别,也可以直接控制指定包对应的日志输出级别
root也相当于一个组,一个大组
logging:
# 设置日志组
group:
# 自定义组名,设置当前组中所包含的包
ebank: com.itheima.controller
# 设置日志级别,root表示根节点,即整体应用日志级别
level:
root: warn
# 为对应组设置日志级别
ebank: debug
# 为对包设置日志级别
com.itheima.service: debug
说白了就是总体设置一下,每个包设置一下,如果感觉设置的麻烦,就先把包分个组,对组设置,没了,就这些。
总结
导入lombok日志类之后,直接使用@Slf4j注解打印日志
@RestController
@RequestMapping("/books")
public class BookController extends BaseClass{
private static final Logger log = LoggerFactory.getLogger(BookController.class); //这一句可以不写了
}
导入lombok后使用注解搞定,日志对象名为log
总结
日志已经能够记录了,但是目前记录的格式是SpringBoot给我们提供的,如果想自定义控制就需要自己设置了。先分析一下当前日志的记录格式。
日志信息为各个类中调用log的相应方法打出来的方法
对于单条日志信息来说,日期,触发位置,记录信息是最核心的信息。级别用于做筛选过滤,PID与线程名用于做精准分析。了解这些信息后就可以DIY日志格式了。本课程不做详细的研究,有兴趣的小伙伴可以学习相关的知识。下面给出课程中模拟的官方日志模板的书写格式,便于大家学习。
logging:
pattern:
console: "%d %clr(%p) --- [%16t] %clr(%-40.40c){cyan} : %m %n"
总结
研究日志转存格式
记录日志到文件中格式非常简单,设置日志文件名即可。
logging:
file:
name: server.log
虽然使用上述格式可以将日志记录下来了,但是面对线上的复杂情况,一个文件记录肯定是不能够满足运维要求的,通常会每天记录日志文件,同时为了便于维护,还要限制每个日志文件的大小。下面给出日志文件的常用配置方式:
logging:
logback:
rollingpolicy:
max-file-size: 3KB
file-name-pattern: server.%d{yyyy-MM-dd}.%i.log
以上格式是基于logback日志技术设置每日日志文件的设置格式,要求容量到达3KB以后就转存信息到第二个文件中。文件命名规则中的%d标识日期,%i是一个递增变量,用于区分日志文件。
总结
运维实用篇到这里就要先告一段落了,为什么不说结束呢?因为运维篇中还有一些知识,但是现在讲解过于分散了。所以要把这些知识与开发实用篇的知识结合在一起讲,也是本课程的教学设计的体现。
在整体运维实用篇中带着大家学习了4块内容,首先学习了如何运行SpringBoot程序,也就是程序的打包与运行,接下来对配置进行了升级学习,不再局限在配置文件中进行设置,通过临时属性,外部配置文件对项目的配置进行管控。在多环境开发中给大家介绍了多种多环境开发的格式,其实掌握一种即可,此外还给大家讲了多环境开发的一些技巧以及与maven的冲突解决方案。最后给大家介绍了日志系统,老实说日志这里讲的相当的潦草,因为大部分日志相关的知识都不应该在这门课中学习,这里只是告诉大家如何整合实用而已。
name: server.log
虽然使用上述格式可以将日志记录下来了,但是面对线上的复杂情况,一个文件记录肯定是不能够满足运维要求的,通常会每天记录日志文件,同时为了便于维护,还要限制每个日志文件的大小。下面给出日志文件的常用配置方式:
```YAML
logging:
logback:
rollingpolicy:
max-file-size: 3KB
file-name-pattern: server.%d{yyyy-MM-dd}.%i.log
以上格式是基于logback日志技术设置每日日志文件的设置格式,要求容量到达3KB以后就转存信息到第二个文件中。文件命名规则中的%d标识日期,%i是一个递增变量,用于区分日志文件。
总结
[外链图片转存中…(img-w19Wz0a7-1688197154374)]
运维实用篇到这里就要先告一段落了,为什么不说结束呢?因为运维篇中还有一些知识,但是现在讲解过于分散了。所以要把这些知识与开发实用篇的知识结合在一起讲,也是本课程的教学设计的体现。
在整体运维实用篇中带着大家学习了4块内容,首先学习了如何运行SpringBoot程序,也就是程序的打包与运行,接下来对配置进行了升级学习,不再局限在配置文件中进行设置,通过临时属性,外部配置文件对项目的配置进行管控。在多环境开发中给大家介绍了多种多环境开发的格式,其实掌握一种即可,此外还给大家讲了多环境开发的一些技巧以及与maven的冲突解决方案。最后给大家介绍了日志系统,老实说日志这里讲的相当的潦草,因为大部分日志相关的知识都不应该在这门课中学习,这里只是告诉大家如何整合实用而已。