• SpringBoot【运维实用篇】


    1.SpringBoot程序的打包与运行

    刚开始做开发学习的小伙伴可能在有一个知识上面有错误的认知,我们天天写程序是在Idea下写的,运行也是在Idea下运行的。

    但是实际开发完成后,我们的项目是不可能运行在自己的电脑上的。

    我们以后制作的程序是运行在专用的服务器上的,简单说就是将你做的程序放在一台独立运行的电脑上,这台电脑要比你开发使用的计算机更专业,并且安全等级各个方面要远超过你现在的电脑。

    那我们的程序如何放置在这台专用的电脑上呢,这就要将我们的程序先组织成一个文件,然后将这个文件传输到这台服务器上。这里面就存在两个过程,一个是打包的过程,另一个是运行的过程。

    温馨提示

    企业项目上线为了保障环境适配性会采用下面流程发布项目,这里不讨论此过程。

    1. 开发部门使用Git、SVN等版本控制工具上传工程到版本服务器

    2. 服务器使用版本控制工具下载工程

    3. 服务器上使用Maven工具在当前真机环境下重新构建项目

    4. 启动服务

    程序打包

    所谓打包指将程序转换成一个可执行的文件,所谓运行指不依赖开发环境执行打包产生的文件。

    SpringBoot程序是基于Maven创建的,在Maven中提供有打包的指令,叫做package。本操作可以在Idea环境下执行。

    mvn package

    打包后会产生一个与工程名类似的jar文件,其名称是由模块名+版本号+.jar组成的。

    程序运行

    程序包打好以后,就可以直接执行了。在程序包所在路径下,执行指令。

    java -jar 工程包名.jar

    执行程序打包指令后,程序正常运行,与在Idea下执行程序没有区别。

    特别关注:如果你的计算机中没有安装java的jdk环境,是无法正确执行上述操作的,因为程序执行使用的是java指令。

    特别关注:在使用向导创建SpringBoot工程时,pom.xml文件中会有如下配置,这一段配置千万不能删除,否则打包后无法正常执行程序。

    1. <build>
    2. <plugins>
    3. <plugin>
    4. <groupId>org.springframework.boot</groupId>
    5. <artifactId>spring-boot-maven-plugin</artifactId>
    6. </plugin>
    7. </plugins>
    8. </build>

    总结

    1. SpringBoot工程可以基于java环境下独立运行jar文件启动服务

    2. SpringBoot工程执行mvn命令package进行打包

    3. 执行jar命令:java –jar 工程名.jar

    SpringBoot程序打包失败处理

    在SpringBoot工程的pom.xml中有下面这组配置,这组配置决定了打包出来的程序包是否可以执行。

    1. <build>
    2. <plugins>
    3. <plugin>
    4. <groupId>org.springframework.bootgroupId>
    5. <artifactId>spring-boot-maven-pluginartifactId>
    6. plugin>
    7. plugins>
    8. build>

    我们分别开启这段配置和注释掉这段配置分别执行两次打包,然后观察两次打包后的程序包的差别,共有3处比较明显的特征

    • 打包后文件的大小不同

    • 打包后所包含的内容不同

    • 打包程序中个别文件内容不同

    先看第一个现象,文件大小不同。带有配置时打包生成的程序包大小如下:

    我们发现内容也完全不一样,仅有一个目录是一样的,叫做META-INF。打开容量大的程序包中的BOOT-INF目录下的classes目录,我们发现其中的内容居然和容量小的程序包中的内容完全一样。

    原来大的程序包中除了包含小的程序包中的内容,还有别的东西。都有什么呢?回到BOOT-INF目录下,打开lib目录,里面显示了很多个jar文件。

    仔细翻阅不难发现,这些jar文件都是我们制作这个工程时导入的坐标对应的文件。大概可以想明白了,SpringBoot程序为了让自己打包生成的程序可以独立运行,不仅将项目中自己开发的内容进行了打包,还把当前工程运行需要使用的jar包全部打包进来了。为什么这样做呢?就是为了可以独立运行。不依赖程序包外部的任何资源可以独立运行当前程序。这也是为什么大的程序包容量是小的程序包容量的30倍的主要原因。

    再看看大程序包还有什么不同之处,在最外层目录包含一个org目录,进入此目录,目录名是org\springframework\boot\loader,在里面可以找到一个JarLauncher.class的文件,先记得这个文件。再看这套目录名,明显是一个Spring的目录名,为什么要把Spring框架的东西打包到这个程序包中呢?不清楚。

    回到两个程序包的最外层目录,查看名称相同的文件夹META-INF下都有一个叫做MANIFEST.MF的文件,但是大小不同,打开文件,比较内容区别

    • 小容量文件的MANIFEST.MF

    1. Manifest-Version: 1.0
    2. Implementation-Title: springboot_08_ssmp
    3. Implementation-Version: 0.0.1-SNAPSHOT
    4. Build-Jdk-Spec: 1.8
    5. Created-By: Maven Jar Plugin 3.2.0
    • 大容量文件的MANIFEST.MF
    1. Manifest-Version: 1.0
    2. Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
    3. Implementation-Title: springboot_08_ssmp
    4. Implementation-Version: 0.0.1-SNAPSHOT
    5. Spring-Boot-Layers-Index: BOOT-INF/layers.idx
    6. Start-Class: com.itheima.SSMPApplication
    7. Spring-Boot-Classes: BOOT-INF/classes/
    8. Spring-Boot-Lib: BOOT-INF/lib/
    9. Build-Jdk-Spec: 1.8
    10. Spring-Boot-Version: 2.5.4
    11. Created-By: Maven Jar Plugin 3.2.0
    12. Main-Class: org.springframework.boot.loader.JarLauncher

    大文件中明显比小文件中多了几行信息,其中最后一行信息是Main-Class: org.springframework.boot.loader.JarLauncher。这句话什么意思呢?如果使用java -jar执行此程序包,将执行Main-Class属性配置的类,这个类恰巧就是前面看到的那个文件。原来SpringBoot打包程序中出现Spring框架的东西是为这里服务的。而这个org.springframework.boot.loader.JarLauncher类内部要查找Start-Class属性中配置的类,并执行对应的类。这个属性在当前配置中也存在,对应的就是我们的引导类类名。

    现在这组设定的作用就搞清楚了

    1. SpringBoot程序添加配置后会打出一个特殊的包,包含Spring框架部分功能,原始工程内容,原始工程依赖的jar包

    2. 首先读取MANIFEST.MF文件中的Main-Class属性,用来标记执行java -jar命令后运行的类

    3. JarLauncher类执行时会找到Start-Class属性,也就是启动类类名

    4. 运行启动类时会运行当前工程的内容

    5. 运行当前工程时会使用依赖的jar包,从lib目录中查找

    看来SpringBoot打出来了包为了能够独立运行,简直是煞费苦心,将所有需要使用的资源全部都添加到了这个包里。这就是为什么这个jar包能独立运行的原因。

    再来看之前的报错信息:

    由于打包时没有使用那段配置,结果打包后形成了一个普通的jar包,在MANIFEST.MF文件中也就没有了Main-Class对应的属性了,所以运行时提示找不到主清单属性,这就是报错的原因。

    上述内容搞清楚对我们编程意义并不大,但是对各位小伙伴理清楚SpringBoot工程独立运行的机制是有帮助的。其实整体过程主要是带着大家分析,如果以后遇到了类似的问题,多给自己提问,多问一个为什么,兴趣自己就可以独立解决问题了。

    总结

    1. spring-boot-maven-plugin插件用于将当前程序打包成一个可以独立运行的程序包

    命令行启动常见问题及解决方案

    各位小伙伴在DOS环境下启动SpringBoot工程时,可能会遇到端口占用的问题。给大家一组命令,不用深入学习,备用吧。

    1. # 查询端口
    2. netstat -ano
    3. # 查询指定端口
    4. netstat -ano |findstr "端口号"
    5. # 根据进程PID查询进程名称
    6. tasklist |findstr "进程PID号"
    7. # 根据PID杀死任务
    8. taskkill /F /PID "进程PID号"
    9. # 根据进程名称杀死任务
    10. taskkill -f -t -im "进程名称"

    2.配置高级

    1.临时属性设置

    目前我们的程序包打好了,可以发布了。但是程序包打好以后,里面的配置都已经是固定的了,比如配置了服务器的端口是8080。如果我要启动项目,发现当前我的服务器上已经有应用启动起来并且占用了8080端口,这个时候就尴尬了。难道要重新把打包好的程序修改一下吗?比如我要把打包好的程序启动端口改成80。

    java –jar springboot.jar –-server.port=80

    上面的命令是启动SpringBoot程序包的命令,在命令输入完毕后,空一格,然后输入两个-号。下面按照属性名=属性值的形式添加对应参数就可以了。记得,这里的格式不是yaml中的书写格式,当属性存在多级名称时,中间使用点分隔,和properties文件中的属性格式完全相同。

    如果你发现要修改的属性不止一个,可以按照上述格式继续写,属性与属性之间使用空格分隔。

    java –jar springboot.jar –-server.port=80 --logging.level.root=debug

    2. 属性加载优先级

    现在我们的程序配置受两个地方控制了,第一配置文件,第二临时属性。并且我们发现临时属性的加载优先级要高于配置文件的。

    官方文档:

    https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config

    比如你现在加载了一个user.name属性。结果你发现出来的结果和你想的不一样,那肯定是别的优先级比你高的属性覆盖你的配置属性了,那你就可以看着这个顺序挨个排查。哪个位置有可能覆盖了你的属性。

    总结

    1. 使用jar命令启动SpringBoot工程时可以使用临时属性替换配置文件中的属性

    2. 临时属性添加方式:java –jar 工程名.jar –-属性名=值

    3. 多个临时属性之间使用空格分隔

    4. 临时属性必须是当前boot工程支持的属性,否则设置无效

    3. 开发环境中使用临时属性

    打开SpringBoot引导类的运行界面,在里面找到配置项。其中Program arguments对应的位置就是添加临时属性的,可以加几个试试效果。

    如果想使用main方法的参数,也就是下面的args参数,就是在上面这个位置添加的参数。

    1. public static void main(String[] args) {
    2. }

    原来是这样,通过这个args就可以获取到参数。再来看我们的引导类是如何书写的

    1. public static void main(String[] args) {
    2. SpringApplication.run(SSMPApplication.class,args);
    3. }

    将配置不写在配置文件中,直接写成一个字符串数组,传递给程序入口。当然,这种做法并没有什么实际开发意义。

    1. public static void main(String[] args) {
    2. String[] arg = new String[1];
    3. arg[0] = "--server.port=8082";
    4. SpringApplication.run(SSMPApplication.class, arg);
    5. }

    总结

    1. 启动SpringBoot程序时,可以选择是否使用命令行属性为SpringBoot程序传递启动属性

    思考

    现在使用临时属性可以在启动项目前临时更改配置了,但是新的问题又出来了。临时属性好用是好用,就是写的多了会很麻烦。比如我现在有个需求,上线的时候使用临时属性配置20个值,这下可麻烦了,能不能搞得简单点,集中管理一下呢?比如说搞个文件,加载指定文件?

    4. 配置文件分类

    SpringBoot提供的4级配置文件中的其中一个级别。4个级别分别是:

    • 类路径下配置文件(一直使用的是这个,也就是resources目录中的application.yml文件)

    • 类路径下config目录下配置文件

    • 程序包所在目录中配置文件

    • 程序包所在目录中config目录下配置文件【一定要叫“config”】

    优先顺序

    1. file :config/application.yml 【最高】

    2. file :application.yml

    3. classpath:config/application.yml

    4. classpath:application.yml 【最低】

    级别1和2什么时候使用呢?程序打包以后就要用这个级别了,管你程序里面配置写的是什么?我的级别高,可以轻松覆盖你,就不用考虑这些配置冲突的问题了。

    总结

    1. 配置文件分为4种

      • 项目类路径配置文件:服务于开发人员本机开发与测试

    • 项目类路径config目录中配置文件:服务于项目经理整体调控

    • 工程路径配置文件:服务于运维人员配置涉密线上环境

    • 工程路径config目录中配置文件:服务于运维经理整体调控

          多层级配置文件间的属性采用叠加并覆盖的形式作用于程序

    5.自定义配置文件

    自定义配置文件方式有如下两种:

    方式一:使用临时属性设置配置文件名,注意仅仅是名称,不要带扩展名

    方式二:使用临时属性设置配置文件路径,这个是全路径名

    也可以设置加载多个配置文件

    使用的属性一个是spring.config.name,另一个是spring.config.location,这个一定要区别清楚。【最终生效的是最后一个classpath】

    温馨提示

    我们现在研究的都是SpringBoot单体项目,就是单服务器版本。其实企业开发现在更多的是使用基于SpringCloud技术的多服务器项目。这种配置方式和我们现在学习的完全不一样,所有的服务器将不再设置自己的配置文件,而是通过配置中心获取配置,动态加载配置信息。为什么这样做?集中管理。这里不再说这些了,后面再讲这些东西。

    总结

    1. 配置文件可以修改名称,通过启动参数设定

    2. 配置文件可以修改路径,通过启动参数设定

    3. 微服务开发中配置文件通过配置中心进行设置

    3. 多环境开发

    什么是多环境?其实就是说你的电脑上写的程序最终要放到别人的服务器上去运行。每个计算机环境不一样,这就是多环境。常见的多环境开发主要兼顾3种环境设置,开发环境——自己用的,测试环境——自己公司用的,生产环境——甲方爸爸用的。因为这是绝对不同的三台电脑,所以环境肯定有所不同,比如连接的数据库不一样,设置的访问端口不一样等等。

    1.多环境开发(yaml单一文件版)

    那什么是多环境开发?就是针对不同的环境设置不同的配置属性即可。比如你自己开发时,配置你的端口如下:

    1. server:
    2. port: 80

    如何想设计两组环境呢?中间使用三个减号分隔开

    1. server:
    2. port: 80
    3. ---
    4. server:
    5. port: 81

    如何区分两种环境呢?起名字呗

    1. spring:
    2. profiles: pro
    3. server:
    4. port: 80
    5. ---
    6. spring:
    7. profiles: dev
    8. server:
    9. port: 81

    那用哪一个呢?设置默认启动哪个就可以了

    1. spring:
    2. profiles:
    3. active: pro # 启动pro
    4. ---
    5. spring:
    6. profiles: pro
    7. server:
    8. port: 80
    9. ---
    10. spring:
    11. profiles: dev
    12. server:
    13. port: 81
    1. spring:
    2. profiles:
    3. active: pro # 启动pro
    4. ---
    5. spring:
    6. profiles: pro
    7. server:
    8. port: 80
    9. ---
    10. spring:
    11. profiles: dev
    12. server:
    13. port: 81
    14. ---
    15. spring:
    16. profiles: test
    17. server:
    18. port: 82

    其中关于环境名称定义上述格式是过时格式,标准格式如下

    1. spring:
    2. config:
    3. activate:
    4. on-profile: pro

    总结

    1. 多环境开发需要设置若干种常用环境,例如开发、生产、测试环境

    2. yaml格式中设置多环境使用---区分环境设置边界

    3. 每种环境的区别在于加载的配置属性不同

    4. 启用某种环境时需要指定启动时使用该环境

    2.多环境开发(yaml多文件版)

    将所有的配置都放在一个配置文件中,尤其是每一个配置应用场景都不一样,这显然不合理,于是就有了将一个配置文件拆分成多个配置文件的想法。拆分后,每个配置文件中写自己的配置,主配置文件中写清楚用哪一个配置文件就好了。

    主配置文件

    1. spring:
    2. profiles:
    3. active: pro # 启动pro

    环境配置文件

    1. server:
    2. port: 80

    环境配置文件因为每一个都是配置自己的项,所以连名字都不用写里面了。那问题是如何区分这是哪一组配置呢?使用文件名区分。

    application-pro.yaml

    1. server:
    2. port: 80

    application-dev.yaml

    1. server:
    2. port: 81

    文件的命名规则为:application-环境名.yml

    在配置文件中,如果某些配置项所有环境都一样,可以将这些项写入到主配置中,只有哪些有区别的项才写入到环境配置文件中。

    • 主配置文件中设置公共配置(全局)

    • 环境分类配置文件中常用于设置冲突属性(局部)

    总结

    1. 可以使用独立配置文件定义环境属性

    2. 独立配置文件便于线上系统维护更新并保障系统安全性

    3.多环境开发(properties多文件版)

    SpringBoot最早期提供的配置文件格式是properties格式的,这种格式的多环境配置也了解一下吧。

    主配置文件

    spring.profiles.active=pro

    环境配置文件

    application-pro.properties

    server.port=80

    application-dev.properties

    server.port=81

    文件的命名规则为:application-环境名.properties。

    总结

    1. properties文件多环境配置仅支持多文件格式

    4.多环境开发独立配置文件书写技巧

    准备工作

    将所有的配置根据功能对配置文件中的信息进行拆分,并制作成独立的配置文件,命名规则如下

    • application-devDB.yml

    • application-devRedis.yml

    • application-devMVC.yml

    使用:include【只能指定一个环境】

    使用include属性在激活指定环境的情况下,同时对多个环境进行加载使其生效,多个环境间使用逗号分隔

    1. spring:
    2. profiles:
    3. active: dev
    4. include: devDB,devRedis,devMVC

    比较一下,现在相当于加载dev配置时,再加载对应的3组配置,从结构上就很清晰,用了什么,对应的名称是什么

    注意

    当主环境dev与其他环境有相同属性时,主环境属性生效;其他环境中有相同属性时,最后加载的环境属性生效

    改良:group【可以指定多个环境】

    但是上面的设置也有一个问题,比如我要切换dev环境为pro时,include也要修改。因为include属性只能使用一次,这就比较麻烦了。SpringBoot从2.4版开始使用group属性替代include属性,降低了配置书写量。简单说就是我先写好,你爱用哪个用哪个。

    1. spring:
    2. profiles:
    3. active: dev
    4. group:
    5. "dev": devDB,devRedis,devMVC
    6. "pro": proDB,proRedis,proMVC
    7. "test": testDB,testRedis,testMVC

    现在再来看,如果切换dev到pro,只需要改一下是不是就结束了?完美!

    总结

    1. 多环境开发使用group属性设置配置文件分组,便于线上维护管理【添加多个配置文件】

    2. 当主环境dev与其他环境有相同属性时,主环境属性生效;其他环境中有相同属性时,最后加载的环境属性生效

    5.多环境开发控制

    最后说一个冲突问题。就是maven和SpringBoot同时设置多环境的话怎么搞。

    maven中设置多环境(使用属性方式区分环境)

    1. <profiles>
    2. <profile>
    3. <id>env_devid>
    4. <properties>
    5. <profile.active>devprofile.active>
    6. properties>
    7. <activation>
    8. <activeByDefault>trueactiveByDefault>
    9. activation>
    10. profile>
    11. <profile>
    12. <id>env_proid>
    13. <properties>
    14. <profile.active>proprofile.active>
    15. properties>
    16. profile>
    17. <profile>
    18. <id>test_envid>
    19. <properties>
    20. <profile.active>testprofile.active>
    21. properties>
    22. profile>
    23. profiles>

    SpringBoot中读取maven设置值

    1. spring:
    2. profiles:
    3. active: @profile.active@

    上面的@属性名@就是读取maven中配置的属性值的语法格式。

    总结

    1. 当Maven与SpringBoot同时对多环境进行控制时,以Mavn为主,SpringBoot使用@..@占位符读取Maven对应的配置属性值

    2. 基于SpringBoot读取Maven配置属性的前提下,如果在Idea下测试工程时pom.xml每次更新需要手动compile方可生效

    4.日志

    1.代码中使用日志工具记录日志

    日志的使用格式非常固定,直接上操作步骤:

    步骤①:添加日志记录操作

    1. @RestController
    2. @RequestMapping("/books")
    3. public class BookController extends BaseClass{
    4. private static final Logger log = LoggerFactory.getLogger(BookController.class);
    5. @GetMapping
    6. public String getById(){
    7. log.debug("debug...");
    8. log.info("info...");
    9. log.warn("warn...");
    10. log.error("error...");
    11. return "springboot is running...2";
    12. }
    13. }

    步骤②:设置日志输出级别

    日志设置好以后可以根据设置选择哪些参与记录。这里是根据日志的级别来设置的。日志的级别分为6种,分别是:

    • TRACE:运行堆栈信息,使用率低

    • DEBUG:程序员调试代码使用

    • INFO:记录运维过程数据

    • WARN:记录运维过程报警数据

    • ERROR:记录错误堆栈信息

    • FATAL:灾难信息,合并计入ERROR

    一般情况下,开发时候使用DEBUG,上线后使用INFO,运维信息记录使用WARN即可。下面就设置一下日志级别:

    1. # 开启debug模式,输出调试信息,常用于检查系统运行状况
    2. debug: true

    这么设置太简单粗暴了,日志系统通常都提供了细粒度的控制

    1. # 开启debug模式,输出调试信息,常用于检查系统运行状况
    2. debug: true
    3. # 设置日志级别,root表示根节点,即整体应用日志级别
    4. logging:
    5. level:
    6. root: debug

    说白了就是总体设置一下,每个包设置一下,如果感觉设置的麻烦,就先把包分个组,对组设置,没了,就这些。

    总结

    1. 日志用于记录开发调试与运维过程消息

    2. 日志的级别共6种,通常使用4种即可,分别是DEBUG,INFO,WARN,ERROR

    3. 可以通过日志组或代码包的形式进行日志显示级别的控制

    2. 使用Lombok注解进行日志输出:@Slf4j

    1. @RestController
    2. @RequestMapping("/books")
    3. public class BookController extends BaseClass{
    4. private static final Logger log = LoggerFactory.getLogger(BookController.class); //这一句可以不写了
    5. }

    导入lombok后使用注解搞定,日志对象名为log

    1. @Slf4j //这个注解替代了下面那一行
    2. @RestController
    3. @RequestMapping("/books")
    4. public class BookController extends BaseClass{
    5. private static final Logger log = LoggerFactory.getLogger(BookController.class); //这一句可以不写了
    6. }

    总结

    1. 基于lombok提供的@Slf4j注解为类快速添加日志对象

    3.日志输出格式控制

    日志已经能够记录了,但是目前记录的格式是SpringBoot给我们提供的,如果想自定义控制就需要自己设置了。先分析一下当前日志的记录格式。

    %d:日期

    %p:日志运行级别

    %clr:日志颜色

    %c:类名

    %m:消息

    %n:换行

    %-40.40c:表示获取四十位

    {cyan}:指定颜

    1. logging:
    2. pattern:
    3. console: "%d %clr(%p) --- [%16t] %clr(%-40.40c){cyan} : %m %n"

    4.日志文件

    日志不能仅显示在控制台上,要把日志记录到文件中,方便后期维护查阅。

    记录日志到文件中格式非常简单,设置日志文件名即可。

    1. logging:
    2. file:
    3. # 日志文件名
    4. name: server.log

    虽然使用上述格式可以将日志记录下来了,但是面对线上的复杂情况,一个文件记录肯定是不能够满足运维要求的,通常会每天记录日志文件,同时为了便于维护,还要限制每个日志文件的大小。下面给出日志文件的常用配置方式:

    %i:表示第一个

    1. logging:
    2. logback:
    3. # 一天一个文件
    4. rollingpolicy:
    5. max-file-size: 3KB
    6. file-name-pattern: server.%d{yyyy-MM-dd}.%i.log

    以上格式是基于logback日志技术设置每日日志文件的设置格式,要求容量到达3KB以后就转存信息到第二个文件中。文件命名规则中的%d标识日期,%i是一个递增变量,用于区分日志文件。

    总结

    1. 日志记录到文件

    2. 日志文件格式设置

  • 相关阅读:
    助力生成式AI人才培养,飞桨(湖北)教育创新中心启动建设
    笔记38:膨胀卷积/空洞卷积的原理
    01 MongoDB的概述、应用场景、下载方式、连接方式和发展历史等
    web前端-javascript-基本语法(注释,常用语法,代码格式)
    微信网页版能够使用(会顶掉微信app的登陆)
    1.1.3开发基础-硬件-示波器
    短视频无尽流前端开发指南
    适用于 Windows 10 和 Windows 11 设备的笔记本电脑管理软件
    2018-Adversarial Learning for Semi-Supervised Semantic Segmentation
    【Linux】自制shell
  • 原文地址:https://blog.csdn.net/m0_63077733/article/details/132797586