实际开发完成后,我们的项目是不可能运行在自己的电脑上的,需要运行在专用的服务器上的。这就要将我们的程序先组织成一个文件,然后将这个文件传输到这台服务器上。这里面就存在两个过程,一个是打包的过程,另一个是运行的过程。
SpringBoot程序是基于Maven创建的,在Maven中提供有打包的指令,叫做package。
mvn package
也可以直接使用maven插件:
打包后会产生一个与工程名类似的jar文件,其名称是由模块名+版本号+.jar组成的。
程序包打好以后,在程序包所在路径下,执行指令,程序正常运行,与在Idea下执行程序没有区别。
java -jar 工程包名.jar
注意: 如果计算机中没有安装java的jdk环境,是无法正确执行上述操作的,因为程序执行使用的是java指令。
注意: 在使用向导创建SpringBoot工程时,pom.xml文件中会有如下配置,这一段配置千万不能删除,否则打包后无法正常执行程序。
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
打包以后执行会下面的问题,导致程序无法正常执行:
在SpringBoot工程的pom.xml中有下面这组配置,这组配置决定了打包出来的程序包是否可以执行。
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
可执行jar包的目录结构:
lib目录中jar文件都是制作这个工程时导入的坐标对应的文件。SpringBoot程序为了让自己打包生成的程序可以独立运行,不仅将项目中自己开发的内容进行了打包,还把当前工程运行需要使用的jar包全部打包进来了。就是为了可以独立运行。不依赖程序包外部的任何资源可以独立运行当前程序。
其中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
Start-Class: com.itheima.SSMPApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.5.4
Created-By: Maven Jar Plugin 3.2.0
Main-Class: org.springframework.boot.loader.JarLauncher ##jar启动器
命令行启动常见问题及解决方案:
# 查询端口
netstat -ano
# 查询指定端口
netstat -ano |findstr "端口号"
# 根据进程PID查询进程名称
tasklist |findstr "进程PID号"
# 根据PID杀死任务
taskkill /F /PID "进程PID号"
# 根据进程名称杀死任务
taskkill -f -t -im "进程名称"
SpringBoot提供了灵活的配置方式,如果发现项目中有个别属性需要重新配置,可以使用临时属性的方式快速修改某些配置。在启动的时候添加上对应参数就可以。
java –jar springboot.jar –-server.port=80
当属性存在多级名称时,中间使用点分隔,和properties文件中的属性格式完全相同。
java –jar springboot.jar –-server.port=80 --logging.level.root=debug
属性加载优先级
打开官方文档中对应的内容,就可以查看配置读取的优先顺序:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config
总结:
打开SpringBoot引导类的运行界面,在里面找到配置项。其中Program arguments对应的位置就是添加临时属性的,可以加几个试试效果。
如果对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) {
public static void main(String[] args) {
String[] arg = new String[1];
arg[0] = "--server.port=8083";
SpringApplication.run(SSMPApplication.class, arg);
}
}
SpringBoot提供的4级配置文件分别是:
8085>8084>8083>80
总结
配置文件分为4种
多层级配置文件间的属性采用叠加并覆盖的形式作用于程序
自定义配置文件方式有如下两种:
方式一:使用临时属性设置配置文件名,注意仅仅是名称,不要带扩展名
方式二:使用临时属性设置配置文件路径,这个是全路径名
也可以设置加载多个配置文件:
总结
针对不同的环境设置不同的配置属性即可。比如开发时配置端口如下:
## 设置默认启动哪个配置
spring:
config:
activate:
on-profile: pro
## 中间使用三个减号分隔开不同环境
---
## 起别名区分不同环境
spring:
profiles: pro
server:
port: 80
---
spring:
profiles: dev
server:
port: 81
---
spring:
profiles: test
server:
port: 82
总结
将所有的配置都放在一个配置文件中,尤其是每一个配置应用场景都不一样,这显然不合理,于是就有了将一个配置文件拆分成多个配置文件的想法。拆分后,每个配置文件中写自己的配置,主配置文件中写清楚用哪一个配置文件就好了。
主配置文件:
spring:
profiles:
active: pro # 启动pro
环境配置文件因为每一个都是配置自己的项,所以连名字都不用写里面了。使用文件名区分区分配置。
application-pro.yaml
server:
port: 80
application-dev.yaml
server:
port: 81
文件的命名规则为:application-环境名.yml。
在配置文件中,如果某些配置项所有环境都一样,可以将这些项写入到主配置中,只有哪些有区别的项才写入到环境配置文件中。
备注: properties文件多环境配置仅支持多文件格式
如何基于多环境开发做配置独立管理,首先将所有的配置根据功能对配置文件中的信息进行拆分,并制作成独立的配置文件,命名规则如下
使用include属性在激活指定环境的情况下,同时对多个环境进行加载使其生效,多个环境间使用逗号分隔
spring:
profiles:
active: dev
include: devMVC,devDB
application-dev.yml(加载顺序为3,主配置最后加载)
server:
port: 80
application-devDB.yml(加载顺序为1,先写先加载)
server:
port: 81
application-devMVC.yml(加载顺序为2,后写后加载)
server:
servlet:
context-path: /ebank
port: 82
注意: 当主环境dev与其他环境有相同属性时,主环境属性生效;其他环境中有相同属性时,最后加载的环境属性生效。
但是上面的设置也有一个问题,比如要切换dev环境为pro时,include也要修改。因为include属性只能使用一次,这就比较麻烦了。
SpringBoot从2.4版开始使用group属性替代include属性,降低了配置书写量。主配置先加载
spring:
profiles:
active: dev
group:
"dev": devDB,devMVC
"pro": proDB,proRedis,proMVC
"test": testDB,testRedis,testMVC
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@
"dev": devDB,devMVC
"pro": proDB,proRedis,proMVC
总结
日志其实就是记录程序日常运行的信息,主要作用如下:
1.添加日志记录操作
@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";
}
}
2.设置日志输出级别
可以根据日志的级别来设置哪些参与记录的。日志的级别分为6种,分别是:
一般情况下,开发时候使用DEBUG,上线后使用INFO,运维信息记录使用WARN即可。日志系统通常都提供了细粒度的控制:
# 开启debug模式,输出调试信息,常用于检查系统运行状况
debug: true
# 设置日志级别,root表示根节点,即整体应用日志级别
logging:
level:
root: debug
3.设置日志组,控制指定包对应的日志输出级别,也可以直接控制指定包对应的日志输出级别
logging:
# 设置日志组
group:
# 自定义组名,设置当前组中所包含的包
ebank: com.itheima.controller
level:
root: warn
# 为对应组设置日志级别
ebank: debug
# 为对包设置日志级别
com.itheima.controller: debug
总结
导入lombok后使用注解搞定,日志对象名为log
@Slf4j //这个注解替代了下面那一行
@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";
}
}
日志已经能够记录了,但是目前记录的格式是SpringBoot给我们提供的,如果想自定义控制就需要自己设置了。先分析一下当前日志的记录格式。
于单条日志信息来说,日期,触发位置,记录信息是最核心的信息。级别用于做筛选过滤,PID与线程名用于做精准分析。了解这些信息后就可以DIY日志格式了。下面给出课程中模拟的官方日志模板的书写格式,便于大家学习。
#日志模板
logging:
pattern:
console: "%d %clr(%5p) --- [%16t] %clr(%-40.40c){cyan} : %m %n"
# 时间 显示颜色,占位5 --- [占位16线程名] 显示颜色(左对齐,类名截取40位长):消息 换行
日志不能仅显示在控制台上,要把日志记录到文件中,方便后期维护查阅。对于日志文件的使用存在各种各样的策略,例如每日记录,分类记录,报警后记录等(后续再说)。
记录日志到文件中格式非常简单,设置日志文件名即可。
logging:
file:
name: server.log
虽然使用上述格式可以将日志记录下来了,但是面对线上的复杂情况,一个文件记录肯定是不能够满足运维要求的,通常会每天记录日志文件,同时为了便于维护,还要限制每个日志文件的大小。下面给出日志文件的常用配置方式:
logging:
logback:
rollingpolicy:
max-file-size: 10MB
file-name-pattern: server.%d{yyyy-MM-dd}.%i.log
要求容量到达3KB以后就转存信息到第二个文件中。文件命名规则中的%d标识日期,%i是一个递增变量,用于区分日志文件。