说明:

(1) 本篇博客主要阐述以下的内容:在【Spring Boot电商项目66:上线部署四:把项目部署到服务器;】中,我们在部署项目的时候,使用到了很多命令;这儿对其中使用到的命令,作进一步的详细介绍和分析;

(2)声明: 本篇博客的内容,没必要全部记忆,以能解决目前的疑问为主要目的;

(3) 本篇博客参考的文章有:

●【Linux scp命令】;

●【[3. lsof 一切皆文件](https://linuxtools- rst.readthedocs.io/zh_CN/latest/tool/lsof.html “3. lsof 一切皆文件”)】;

●【java -jar 和 -cp详解】;

●【SpringBoot项目启动指定端口的三种方式】;

●【Linux nohup 命令】;

●【[linux 启动后台服务 nohup

/dev/null](https://blog.csdn.net/ahjxhy2010/article/details/51177327 “linux 启动后台服务 nohup >/dev/null”)】;

(4) 声明:本篇博客可能存在理解存在偏差、缺失甚至错误的地方;但目前,该篇博客能够帮助自己形成自洽;

目录

一:上传文件:scp命令;

二:查看当前系统文件:lsof命令;

三:启动Spring Boot项目的jar,也就是启动Spring Boot项目;

1.java -jar:启动jar包;

2.-Dserver.port=8083:启动时,设置端口号;

3.-Dspring.profiles.active=***:选择配置文件;

4.nohup:以后台的方式,执行某个命令;

(1)第一篇参考博客;

(2)第二篇参考博客; (PS:这儿的理解,可能不太准确;)

5.这儿使用到的启动命令解释;(本篇博客的输出结果)


一:上传文件:scp命令;

我们在 【Spring Boot电商项目66:上线部署四:把项目部署到服务器;】中,是通过Windows的cmd控制台,利用scp命令,向服务器上传文件;

scp -r C:\Users\dell\Desktop\images\. root@4**.***.***.**1:/root/images/


以下内容,参考自【Linux scp命令】;

Linux scp命令 用于在Linux下进行远程拷贝文件的命令,和它类似的命令有[cp](https://www.coonote.com/linux/linux-cmd- cp.html “cp”),不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。可能会稍微影响一下速度。当你服务器硬盘变为只读read only system时,用scp可以帮你把文件移出来。另外,scp还非常不占资源,不会提高多少系统负荷,在这一点上,[rsync](https://www.coonote.com/linux/linux- cmd-rsync.html “rsync”)就远远不及它了。虽然 rsync比scp会快一点,但当小文件众多的情况下,rsync会导致硬盘I/O非常高,而scp基本不影响系统正常使用。

语法

scp  (选项)  (参数)

选项

-1:使用ssh协议版本1;
-2:使用ssh协议版本2;
-4:使用ipv4;
-6:使用ipv6;
-B:以批处理模式运行;
-C:使用压缩;
-F:指定ssh配置文件;
-l:指定宽带限制;
-o:指定使用的ssh选项;
-P:指定远程主机的端口号;
-p:保留文件的最后修改时间,最后访问时间和权限模式;
-q:不显示复制进度;
-r:以递归方式复制。

参数

  • 源文件:指定要复制的源文件。
  • 目标文件:目标文件。格式为user@host:filename(文件名为目标文件的名称)。

实例

从远程复制到本地的scp命令与上面的命令雷同,只要将从本地复制到远程的命令后面2个参数互换顺序就行了。

(1)从远处复制文件到本地目录

scp [email protected]:/opt/soft/nginx-0.5.38.tar.gz /opt/soft/

从10.10.10.10机器上的/opt/soft/的目录中下载nginx-0.5.38.tar.gz 文件到本地/opt/soft/目录中。

(2)从远处复制到本地

scp -r [email protected]:/opt/soft/mongodb /opt/soft/

从10.10.10.10机器上的/opt/soft/中下载mongodb目录到本地的/opt/soft/目录来。

(3)上传本地文件到远程机器指定目录

scp /opt/soft/nginx-0.5.38.tar.gz [email protected]:/opt/soft/scptest

复制本地/opt/soft/目录下的文件nginx-0.5.38.tar.gz到远程机器10.10.10.10的opt/soft/scptest目录。

(4)上传本地目录到远程机器指定目录

scp -r /opt/soft/mongodb [email protected]:/opt/soft/scptest

上传本地目录/opt/soft/mongodb到远程机器10.10.10.10上/opt/soft/scptest的目录中去。


二:查看当前系统文件:lsof命令;

我们在 【Spring Boot电商项目66:上线部署四:把项目部署到服务器;】中,是通过【lsof -i:端口号】命令,查看某端口号,是否有应用占用:


以下内容参考自【[3. lsof 一切皆文件](https://linuxtools- rst.readthedocs.io/zh_CN/latest/tool/lsof.html “3. lsof 一切皆文件”)】;

3. lsof 一切皆文件

lsof(list open files)是一个查看当前系统文件的工具。在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。如传输控制协议 (TCP) 和用户数据报协议 (UDP) 套接字等,系统在后台都为该应用程序分配了一个文件描述符,该文件描述符提供了大量关于这个应用程序本身的信息。

lsof打开的文件可以是:

  1. 普通文件
  2. 目录
  3. 网络文件系统的文件
  4. 字符或设备文件
  5. (函数)共享库
  6. 管道,命名管道
  7. 符号链接
  8. 网络文件(例如:NFS file、网络socket,unix域名socket)
  9. 还有其它类型的文件,等等

3.1. 命令参数

  • -a 列出打开文件存在的进程
  • -c<进程名> 列出指定进程所打开的文件
  • -g 列出GID号进程详情
  • -d<文件号> 列出占用该文件号的进程
  • +d<目录> 列出目录下被打开的文件
  • +D<目录> 递归列出目录下被打开的文件
  • -n<目录> 列出使用NFS的文件
  • -i<条件> 列出符合条件的进程。(4、6、协议、:端口、 @ip )( PS:查看指定端口号的进程,正是我们这儿遇到的情况
  • -p<进程号> 列出指定进程号所打开的文件
  • -u 列出UID号进程详情
  • -h 显示帮助信息
  • -v 显示版本信息

3.2. 使用实例

(1)案例1: 无任何参数;

$lsof| more
COMMAND     PID      USER   FD      TYPE             DEVICE SIZE/OFF

NODE NAME init 1 root cwd DIR 253,0 4096 2 / init 1 root rtd DIR 253,0 4096 2 / init 1 root txt REG 253,0 150352 1310795 /sbin/init init 1 root mem REG 253,0 65928 5505054 /lib64/libnss_files-2.12.so init 1 root mem REG 253,0 1918016 5521405 /lib64/libc-2.12.so init 1 root mem REG 253,0 93224 5521440 /lib64/libgcc_s-4.4.6-20120305.so.1 init 1 root mem REG 253,0 47064 5521407 /lib64/librt-2.12.so init 1 root mem REG 253,0 145720 5521406 /lib64/libpthread-2.12.so

说明:

lsof输出各列信息的意义如下:

  • COMMAND:进程的名称

  • PID:进程标识符

  • PPID:父进程标识符(需要指定-R参数)

  • USER:进程所有者

  • PGID:进程所属组

  • FD:文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等:

(1)cwd:表示current work dirctory,即:应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改
(2)txt :该类型的文件是程序代码,如应用程序二进制文件本身或共享库,如上列表中显示的 /sbin/init 程序
(3)lnn:library references (AIX);
(4)er:FD information error (see NAME column);
(5)jld:jail directory (FreeBSD);
(6)ltx:shared library text (code and data);
(7)mxx :hex memory-mapped type number xx.
(8)m86:DOS Merge mapped file;
(9)mem:memory-mapped file;
(10)mmap:memory-mapped device;
(11)pd:parent directory;
(12)rtd:root directory;
(13)tr:kernel trace file (OpenBSD);
(14)v86  VP/ix mapped file;
(15)0:表示标准输入
(16)1:表示标准输出
(17)2:表示标准错误
一般在标准输出、标准错误、标准输入后还跟着文件状态模式:r、w、u等
(1)u:表示该文件被打开并处于读取/写入模式
(2)r:表示该文件被打开并处于只读模式
(3)w:表示该文件被打开并处于
(4)空格:表示该文件的状态模式为unknow,且没有锁定
(5)-:表示该文件的状态模式为unknow,且被锁定
同时在文件状态模式后面,还跟着相关的锁
(1)N:for a Solaris NFS lock of unknown type;
(2)r:for read lock on part of the file;
(3)R:for a read lock on the entire file;
(4)w:for a write lock on part of the file;(文件的部分写锁)
(5)W:for a write lock on the entire file;(整个文件的写锁)
(6)u:for a read and write lock of any length;
(7)U:for a lock of unknown type;
(8)x:for an SCO OpenServer Xenix lock on part      of the file;
(9)X:for an SCO OpenServer Xenix lock on the      entire file;
(10)space:if there is no lock.
  • TYPE:文件类型,如DIR、REG等,常见的文件类型:

(1)DIR:表示目录
(2)CHR:表示字符类型
(3)BLK:块设备类型
(4)UNIX: UNIX 域套接字
(5)FIFO:先进先出 (FIFO) 队列
(6)IPv4:网际协议 (IP) 套接字
  • DEVICE:指定磁盘的名称

  • SIZE:文件的大小

  • NODE:索引节点(文件在磁盘上的标识)

  • NAME:打开文件的确切名称

(2)案例2: 查找某个文件相关的进程;

$lsof /bin/bash
COMMAND     PID USER  FD   TYPE DEVICE SIZE/OFF    NODE NAME
mysqld_sa  2169 root txt    REG  253,0   938736 4587562 /bin/bash
ksmtuned   2334 root txt    REG  253,0   938736 4587562 /bin/bash
bash      20121 root txt    REG  253,0   938736 4587562 /bin/bash

(3)案例3: 列出某个用户打开的文件信息;

   $lsof -u username

-u 选项,u是user的缩写

(4)案例4: 列出某个程序进程所打开的文件信息;

$lsof -c mysql

(5)案例5: 列出某个用户以及某个进程所打开的文件信息;

$lsof  -u test -c mysql

(6)案例6: 通过某个进程号显示该进程打开的文件;

$lsof -p 11968

(7)案例7: 列出所有的网络连接;

$lsof -i

(8)案例8: 列出所有tcp 网络连接信息;

$lsof -i tcp

$lsof -n -i tcp
COMMAND     PID  USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
svnserve  11552 weber    3u  IPv4 3799399      0t0  TCP *:svn (LISTEN)
redis-ser 25501 weber    4u  IPv4  113150      0t0  TCP 127.0.0.1:6379

(LISTEN)

(9)案例9: 列出谁在使用某个端口;( PS:查看指定端口号的进程,正是我们这儿遇到的情况

$lsof -i :3306

(10)案例10: 列出某个用户的所有活跃的网络端口;

$lsof -a -u test -i

(11)案例11: 根据文件描述列出对应的文件信息;

$lsof -d description(like 2)

示例:

$lsof -d 3 | grep PARSER1
tail      6499 tde    3r   REG    253,3   4514722     417798

/opt/applog/open/log/HOSTPARSER1_ERROR_141217.log.001

说明: 0表示标准输入,1表示标准输出,2表示标准错误,从而可知:所以大多数应用程序所打开的文件的 FD 都是从 3 开始;

(12)案例12: 列出被进程号为1234的进程所打开的所有IPV4 network files;

$lsof -i 4 -a -p 1234

(13)案例13: 列出目前连接主机nf5260i5-td上端口为:20,21,80相关的所有文件信息,且每隔3秒重复执行;

lsof -i @nf5260i5-td:20,21,80 -r 3

三:启动Spring Boot项目的jar,也就是启动Spring Boot项目;

我们在 【Spring Boot电商项目66:上线部署四:把项目部署到服务器;】中,我们是通过【java -jar】命令,启动我们的Spring Boot项目;

nohup java -jar -Dserver.port=8083 -Dspring.profiles.active=prod

/root/mall-0.0.1-SNAPSHOT.jar > /root/null 2>&1 &

其中,使用到了nohup、java -jar等;我们需要详细分析一下;

1.java -jar:启动jar包;

参考自【java -jar 和 -cp详解】,该文的作者是【叫我阿柒啊2021】;

声明:(1)这篇博客中,遇到不是特别清楚的也没事;目前来说,能够说明【java -jar】命令,是启动jar包的,就足够了;(2)【java -jar】主要是启动jar,而其中主要就是:JVM把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载过程;;;所以,要想真正的比较透彻的理解这个问题,后续就需要深入了解JVM的有关内容;

前言

今天从知乎上看到了java -jar的问题,想起自己刚学java的时候也迷茫过,java -jar和-cp有什么区别。java -jar怎么靠着一个jar包来运行程序的,于是乎就打算总结一下自己的使用经验。

命令行执行程序

假如我们有一个程序,把它打包成Test.jar,如何运行才能成功输出Hello World;

package com.test;
public class Test {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

我们有以下两种方法

1. java -jar Test.jar
2. java -cp com.test.Test Test.jar

(1)方式1:java -jar:

我们解压jar包,META-INF文件夹下都有 MANIFEST.MF ,内容如图:

java -jar就是通过 Main-Class 来找到Test类并执行其中的main(),输出Hello World!如果你的MANIFEST.MF文件中没有Main-Class,就会提示Cant load main- class之类的错误。所以在导出jar包的时候一定要指定main-class。 如图:

(2)方式2:java -cp:

对于java -cp就不需要指定Main- Class来指定入口。因为第一个参数就指定了你的入口类,第二个参数就是你的jar包。它会根据你的jar包找到第一个参数指定的Test类,来输出HelloWorld。

怎么选择

假设我们这个程序的运行需要依赖一个叫Dep.jar的包。 如果我们使用-jar的话,就只能把Dep.jar放到Test.jar中,因为-jar只能指定一个jar包. 如果是使用-cp,我们可以选择将Dep.jar放到Test.jar中,也可以选择使用以下命令来运行:

java -cp com.test.Test Test.jar:Dep.jar

cp其实就是classpath,在linux中多个jar包用 : 分割,代表了程序运行需要的所有jar包。这样就可以不用将所有依赖都放到Test.jar下.这样做的好处就是,假如修改了Test类,只上传修改后的Test.jar到服务器即可,不需要再将所有依赖放到Test.jar中再上传一遍,节约了时间。

言归正传

java -jar执行jar包过程,到底背后有哪些技术步骤:

  1. 通过MANIFEST.MF中的Main-Class找到入口类,启动程序
  2. 启动JVM,分配内存(java内存结构和GC知识)
  3. 根据引用关系加载类(类加载、类加载器、双亲委托机制),初始化静态块等
  4. 执行程序,在虚拟机栈创建方法栈桢,局部变量等信息

2.-Dserver.port=8083:启动时,设置端口号;

参考自【SpringBoot项目启动指定端口的三种方式】;

SpringBoot 项目 启动指定端口 的三种方式:

方式一:

配置文件中添加server.port=8080

server:
  port: 8080
##这儿是yml格式的配置文件啦

方式二:

在命令行中指定启动端口,比如传入参数一server. port=8000

java -jar xxx.jar -- server.port=8000

方式三:

传入虚拟机系统属性-Dserver.port=9000

java -Dserver.port=9000 -jar xxx.jar

3.-Dspring.profiles.active=***:选择配置文件;

设置,启动时,使用哪个配置文件;在【附加:Spring Boot项目:多个配置文件介绍;启动项目时候,怎么选择指定配置文件;】作了一些介绍;

4.nohup:以后台的方式,执行某个命令;

(1)第一篇参考博客;

参考自【Linux nohup 命令】;

(1)nohup简介;

nohup 英文全称 no hang up(不挂起),用于在系统后台不挂断地运行命令,退出终端不会影响程序的运行。

nohup 命令,在默认情况下(非重定向时),会输出一个名叫 nohup.out 的文件到当前目录下,如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。

(2)使用权限: 所有使用者;

(3)语法格式:

 nohup Command [ Arg … ] [ & ]

(4)参数说明:

Command :要执行的命令。

Arg :一些参数,可以指定输出文件。

& :让命令在后台执行,终端退出后命令仍旧执行。

(5)实例:

以下命令在后台执行 root 目录下的 runoob.sh 脚本:

nohup /root/runoob.sh &

在终端如果看到以下输出说明运行成功:

appending output to nohup.out

这时我们打开 root 目录 可以看到生成了 nohup.out 文件。

如果要停止运行,你需要使用以下命令查找到 nohup 运行脚本到 PID,然后使用 kill 命令来删除:

ps -aux | grep "runoob.sh"

参数说明:

  • a : 显示所有程序
  • u : 以用户为主的格式来显示
  • x : 显示所有程序,不区分终端机

另外也可以使用 ps -def | grep “runoob.sh” 命令来查找。

找到 PID 后,就可以使用 kill PID 来删除。

kill -9  进程号PID

以下命令在后台执行 root 目录下的 runoob.sh 脚本,并重定向输入到 runoob.log 文件:

nohup /root/runoob.sh > runoob.log 2>&1 &

2 >&1 解释:

将标准错误 2 重定向到标准输出 &1 ,标准输出 &1 再被重定向输入到 runoob.log 文件中。

  • 0 – stdin (standard input,标准输入)
  • 1 – stdout (standard output,标准输出)
  • 2 – stderr (standard error,标准错误输出)

(2)第二篇参考博客; (PS:这儿的理解,可能不太准确;)

参考自【[linux 启动后台服务 nohup

/dev/null](https://blog.csdn.net/ahjxhy2010/article/details/51177327 “linux 启动后台服务 nohup >/dev/null”)】;这篇博客并没有仔细看,这儿仅仅是结合其中的内容,总结了以下内容;

(1) 使用nohup+Command的时候,我们可以把被调用程序的输出等信息,输出到文件中去;

(2) nohup命令是后台执行程序,运行程序后,一般会生成文件nohup.out,所有标准输出会写入该文件。在如【nohup java -jar -Dserver.port=8083 -Dspring.profiles.active=prod /root/mall-0.0.1-SNAPSHOT.jar > /root/null 2>&1 &】命令中, 有/root/null,将不会产生任何文件。

(3) 其中,我们可以对输出进行设置;

● 0:标准输入;1:标准输出;2:标准错误信息输出;可以用来指定需要重定向的标准输入或输出。

● 在一般使用时,默认的是标准输出,既1。

● 当我们需要特殊用途时,可以使用其他标号。 例如,将某个程序的错误信息输出到log文件中:./program 2>log。这样标准输出还是在屏幕上,但是错误信息会输出到log文件中。

● 另外,也可以实现0,1,2之间的重定向。例如,2>&1:将错误信息重定向到标准输出。

(4) /dev/null :Linux下还有一个特殊的文件/dev/null,它就像一个无底洞,所有重定向到它的信息都会消失得无影无踪。这一点非常有用,当我们不需要回显程序的所有信息时,就可以将输出重定向到/dev/null。

● 如果想要正常输出和错误信息都不显示,则要把标准输出和标准错误都重定向到/dev/null, 例如:# ls 1 >/dev/null _2

/dev/null_;

● 还有一种做法是将错误重定向到标准输出,然后再重定向到 /dev/null,例如:# ls >/dev/null 2>&1;( PS:这正是,我们在【nohup java -jar -Dserver.port=8083 -Dspring.profiles.active=prod /root/mall-0.0.1-SNAPSHOT.jar > /root/null 2>&1 &】中的做法;)注意:此处的顺序不能更改,否则达不到想要的效果,此时先将标准输出重定向到 /dev/null,然后将标准错误重定向到标准输出,由于标准输出已经重定向到了/dev/null,因此标准错误也会重定向到/dev/null,于是一切静悄悄:-)

(5) nohup 结合/dev/null:由于使用nohup时,会自动将输出写入nohup.out文件中,如果文件很大的话,nohup.out就会不停的增大,这是我们不希望看到的,因此,可以利用/dev/null来解决这个问题;

● nohup ./program >/dev/null 2 >log &;:标准错误信息输出到log,标准输出信息输出到null(也就意味着标准输出直接丢弃)

● nohup ./program >/dev/null 2 >&1 &;:将错误重定向到标准输出,然后再重定向到null,也就意味着标准输出和标准错误信息都丢弃;

● nohup php ./ConsumerX.php >> /dev/null &;:标准输出和标准错误信息都不显示;

● nohup /usr/local/php-5.6.7/bin/php ./ConsumerX.php >> /root/Consumer/run.log 2 >&1 &:将错误重定向到标准输出,然后再重定向到 run.log,也就意味着标准输出和标准错误信息都输出到run.log;

5.这儿使用到的启动命令解释;(本篇博客的输出结果)

我们这儿使用的、完整的命令是:

nohup java -jar -Dserver.port=8083 -Dspring.profiles.active=prod

/root/mall-0.0.1-SNAPSHOT.jar > /root/null 2>&1 &

对上面的语句解释如下:

nohup java -jar -Dserver.port=8083 -Dspring.profiles.active=prod /root/mall-0.0.1-SNAPSHOT.jar > /root/null 2 >&1 &

(1)nohup:nohup命令,没什么好说的;

(2)java -jar -Dserver.port=8083 -Dspring.profiles.active=prod /root/mall-0.0.1-SNAPSHOT.jar:将要后台执行的Command命令;

(3)/root/null:Arg参数;在这个过程中,0:标准输入、1:标准输出、2:标准错误信息输出,的,指定输出文件;

(4)2>&1:先将标准输出重定向到 /root/null,然后将标准错误重定向到标准输出,由于标准输出已经重定向到了/root/null,因此标准错误也会重定向到/root/null;

(5)&:让命令在后台执行,终端退出后命令仍旧执行。