springboot执行shell脚本_springboot打包不同环境配置与shell脚本部署

本篇和大家分享的是springboot打包并结合shell脚本命令部署,重点在分享一个shell程序启动工具,希望能便利工作;

  • profiles指定不同环境的配置
  • maven-assembly-plugin打发布压缩包
  • 分享shenniu_publish.sh程序启动工具
  • linux上使用shenniu_publish.sh启动程序

profiles指定不同环境的配置

通常一套程序分为了很多个部署环境:开发,测试,uat,线上 等,我们要想对这些环境区分配置文件,可以通过两种方式:

  • 通过application.yml中编码指定 profile.active=uat 方式指定
  • 通过mvn中profiles来区分不同环境对应的配置文件夹,人工可以手动在idea勾选生成不同环境的包(推荐)

这里我们要讲的是第二种,首先在mvn中配置如下内容:

 1     <profiles>
 2         <profile>
 3             <id>node</id>
 4             <properties>
 5                 <!--传递给脚本的参数值-->
 6                 <activeProfile>node</activeProfile>
 7                 <package-name>${scripts_packageName}</package-name>
 8                 <boot-main>${scripts_bootMain}</boot-main>
 9             </properties>
10             <activation>
11                 <activeByDefault>true</activeByDefault>
12             </activation>
13         </profile>
14         <profile>
15             <id>node1</id>
16             <properties>
17                 <activeProfile>node1</activeProfile>
18                 <package-name>${scripts_packageName}</package-name>
19                 <boot-main>${scripts_bootMain}</boot-main>
20             </properties>
21         </profile>
22         <profile>
23             <id>node2</id>
24             <properties>
25                 <activeProfile>node2</activeProfile>
26                 <package-name>${scripts_packageName}</package-name>
27                 <boot-main>${scripts_bootMain}</boot-main>
28             </properties>
29         </profile>
30     </profiles>

节点粗解:

  • id:用来指定不同环境配置文件所在的目录,如下我这里:

8138b91aaf1c5d2496475bdf829699f5.png
  • properties:该节点中的节点是可作为参数传递给其他配置文件,如我这里的package-name节点值就可以在另外的assembly.xml或者shell脚本文件中通过${package-name}获取到,如下:

da3173cfe02241a7932bf914e06339ac.png
  • activeByDefault:指定默认环境配置文件夹

maven-assembly-plugin打发布压缩包

对于springboot程序打包,可以分为jar和war,这里是jar包;有场景是咋们配置文件或者第三方等依赖包不想放到工程jar中,并且把这些文件压缩成一个zip包,方便上传到linux;此时通过maven-assembly-plugin和maven-jar-plugin就可以做到,mvn的配置如:

 1            <plugin>
 2                 <groupId>org.apache.maven.plugins</groupId>
 3                 <artifactId>maven-jar-plugin</artifactId>
 4                 <version>2.6</version>
 5                 <configuration>
 6                     <archive>
 7                         <addMavenDescriptor>false</addMavenDescriptor>
 8                         <manifest>
 9                             <addClasspath>true</addClasspath>
10                             <classpathPrefix>lib/</classpathPrefix>
11                             <mainClass>${scripts_bootMain}</mainClass>
12                         </manifest>
13                     </archive>
14                     <!--打包排除项-->
15                     <excludes>
16                         <exclude>**/*.yml</exclude>
17                         <exclude>**/*.properties</exclude>
18                         <exclude>**/*.xml</exclude>
19                         <exclude>**/*.sh</exclude>
20                     </excludes>
21                 </configuration>
22                 <executions>
23                     <execution>
24                         <id>make-a-jar</id>
25                         <phase>compile</phase>
26                         <goals>
27                             <goal>jar</goal>
28                         </goals>
29                     </execution>
30                 </executions>
31             </plugin>
32 
33             <plugin>
34                 <groupId>org.apache.maven.plugins</groupId>
35                 <artifactId>maven-assembly-plugin</artifactId>
36                 <version>2.4</version>
37                 <!-- The configuration of the plugin -->
38                 <configuration>
39                     <!-- Specifies the configuration file of the assembly plugin -->
40                     <descriptors>
41                         <descriptor>${project.basedir}/src/main/assembly/assembly.xml</descriptor>
42                     </descriptors>
43                 </configuration>
44                 <executions>
45                     <execution>
46                         <id>make-assembly</id>
47                         <phase>package</phase>
48                         <goals>
49                             <goal>single</goal>
50                         </goals>
51                     </execution>
52                 </executions>
53             </plugin>

值得注意的地方如下几点:

  • mainClass节点:用来指定启动main函数入口类路径,如这里的:com.sm.EurekaServerApplication
  • excludes节点:排除主jar包中配置等一些列后缀文件,因为我们要包这些配置文件放到主包外面
  • descriptor节点:用来指定assembly插件对应的assembly.xml配置文件

有了上面mvn配置,我们还需要assembly.xml的配置,这里提取了结合shell脚本发布程序的配置:

 1 <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 2           xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd
 3 http://maven.apache.org/ASSEMBLY/2.0.0 ">
 4     <id>${activeProfile}</id>
 5     <!--打包成一个用于发布的zip文件-->
 6     <formats>
 7         <format>zip</format>
 8     </formats>
 9     <!--true:zip中生成一级目录(此处屏蔽,配合脚本需要profiles后缀)-->
10     <includeBaseDirectory>false</includeBaseDirectory>
11     <dependencySets>
12         <dependencySet>
13             <!--打包进zip文件的lib目录-->
14             <useProjectArtifact>false</useProjectArtifact>
15             <outputDirectory>${package-name}-${activeProfile}/lib</outputDirectory>
16             <unpack>false</unpack>
17         </dependencySet>
18     </dependencySets>
19 
20     <fileSets>
21         <!-- 配置文件打包进zip文件的conf目录 -->
22         <fileSet>
23             <directory>${project.basedir}/src/main/profiles/${activeProfile}</directory>
24             <outputDirectory>${package-name}-${activeProfile}/conf</outputDirectory>
25             <includes>
26                 <include>**/*</include>
27                 <!--<include>*.xml</include>-->
28                 <!--<include>*.properties</include>-->
29                 <!--<include>*.yml</include>-->
30             </includes>
31         </fileSet>
32 
33         <!--启动脚本打包进zip文件-->
34         <fileSet>
35             <directory>${project.basedir}/src/main/scripts</directory>
36             <outputDirectory></outputDirectory>
37             <includes>
38                 <include>**/*</include>
39             </includes>
40             <!-- 文件文件权限为777 -->
41             <fileMode>777</fileMode>
42             <!-- 目录权限为777  -->
43             <directoryMode>777</directoryMode>
44             <!--脚本中参数变量为pom中的值 关键-->
45             <filtered>true</filtered>
46         </fileSet>
47 
48         <!-- 项目编译出来的jar打包进zip文件 -->
49         <fileSet>
50             <directory>${project.build.directory}</directory>
51             <outputDirectory>${package-name}-${activeProfile}/</outputDirectory>
52             <includes>
53                 <include>*.jar</include>
54             </includes>
55         </fileSet>
56     </fileSets>
57 </assembly>

重点节点介绍:

  • formats节点:把配置文件和jar包等压缩成什么文件格式,这里可以有:zip,tar等
  • fileMode节点:指定scripts目录下脚本文件(这里是:shenniu_publish.sh)在linux上文件权限为777
  • filtered节点:脚本中参数变量为pom的profiles中properties的值(该配置,是把mvn中属性值映射生成到sh文件中,如:${package-name})

完成上面配置后,此时我们可以通过idea上勾选切换不同环境来打zip包,如图:

989c6d541e6277a71567726a93448aea.png

分享shenniu_publish.sh程序启动工具

上面步骤完成了zip格式的发布包,我们再分享下启动程序的shell脚本,该脚本具有的功能如:

  • 解压zip+启动jar包
  • 启动jar包
  • 停止对应jar运行
  • 重启jar程序

目前该shell中封装了两种启动jar命令的方式:

  • java -cp
  • java -jar

如图命令格式:

b376a6c7dbfcfe6ff81b80afe303778d.png

来看全部的shell代码:

  1 #!/usr/bin/env bash
  2 #可变参数变量
  3 languageType="javac" #支持 java,javac,netcore 发布
  4 #参数值由pom文件传递
  5 baseZipName="${package-name}-${activeProfile}" #压缩包名称  publish-test.zip的publish
  6 packageName="${package-name}" #命令启动包名 xx.jar的xx
  7 mainclass="${boot-main}" #java -cp启动时,指定main入口类;命令:java -cp conf;lib*.jar;${packageName}.jar ${mainclass}
  8 
  9 #例子
 10 # baseZipName="publish-test" #压缩包名称  publish-test.zip的publish
 11 # packageName="publish" #命令启动包名 publish.jar的xx
 12 
 13 #固定变量
 14 basePath=$(cd `dirname $0`/; pwd)
 15 baseZipPath="${basePath}/${baseZipName}.zip"  #压缩包路径
 16 baseDirPath="${basePath}" #解压部署磁盘路径
 17 pid= #进程pid
 18 
 19 #解压
 20 function shenniu_unzip()
 21 {
 22     echo "解压---------------------------------------------"
 23     echo "压缩包路径:${baseZipPath}"
 24     if [ ! `find ${baseZipPath}` ]
 25     then
 26         echo "不存在压缩包:${baseZipPath}"
 27     else
 28         echo "解压磁盘路径:${baseDirPath}/${baseZipName}"
 29         echo "开始解压..."
 30 
 31         #解压命令
 32         unzip -od ${baseDirPath}/${baseZipName} ${baseZipPath}
 33 
 34         #设置执行权限
 35         chmod +x ${baseDirPath}/${baseZipName}/${packageName}
 36 
 37         echo "解压完成。"  
 38     fi
 39 }
 40 
 41 #检测pid
 42 function getPid()
 43 {
 44     echo "检测状态---------------------------------------------"
 45     pid=`ps -ef | grep -n ${packageName} | grep -v grep | awk '{print $2}'`
 46     if [ ${pid} ] 
 47     then
 48         echo "运行pid:${pid}"
 49     else
 50         echo "未运行"
 51     fi
 52 }
 53 
 54 #启动程序
 55 function start()
 56 {
 57     #启动前,先停止之前的
 58     stop
 59     if [ ${pid} ]
 60     then
 61         echo "停止程序失败,无法启动"
 62     else
 63         echo "启动程序---------------------------------------------"
 64         
 65         #选择语言类型
 66         read -p "输入程序类型(java,javac,netcore),下一步按回车键(默认:${languageType}):" read_languageType
 67         if [ ${read_languageType} ]
 68         then
 69             languageType=${read_languageType}
 70         fi
 71         echo "选择程序类型:${languageType}"
 72 
 73         #进入运行包目录
 74         cd ${baseDirPath}/${baseZipName}
 75 
 76         #分类启动
 77         if [ "${languageType}" == "javac" ] 
 78         then
 79             if [ ${mainclass} ] 
 80             then
 81                 nohup java -cp conf:lib*.jar:${packageName}.jar ${mainclass} >${baseDirPath}/${packageName}.out 2>&1 &
 82                #nohup java -cp conf:lib*.jar:${packageName}.jar ${mainclass} >/dev/null 2>&1 &
 83             fi
 84         elif [ "${languageType}" == "java" ] 
 85         then
 86             nohup java -jar ${baseDirPath}/${baseZipName}/${packageName}.jar >/dev/null 2>&1 &
 87             # java -jar ${baseDirPath}/${baseZipName}/${packageName}.jar
 88         elif [ "${languageType}" == "netcore" ] 
 89         then
 90             #nohup dotnet run ${baseDirPath}/${baseZipName}/${packageName} >/dev/null 2>&1 &
 91             nohup ${baseDirPath}/${baseZipName}/${packageName} >/dev/null 2>&1 &
 92         fi
 93 
 94         #查询是否有启动进程
 95         getPid
 96         if [ ${pid} ]
 97         then
 98             echo "已启动"
 99             #nohup日志
100             tail -n 50 -f ${baseDirPath}/${packageName}.out
101         else
102             echo "启动失败"
103         fi
104     fi
105 }
106 
107 #停止程序
108 function stop()
109 {
110     getPid
111     if [ ${pid} ] 
112     then
113         echo "停止程序---------------------------------------------"
114         kill -9 ${pid}
115         
116         getPid
117         if [ ${pid} ] 
118         then
119             #stop
120             echo "停止失败"
121         else
122             echo "停止成功"
123         fi
124     fi
125 }
126 
127 #启动时带参数,根据参数执行
128 if [ ${#} -ge 1 ] 
129 then
130     case ${1} in
131         "start") 
132             start
133         ;;
134         "restart") 
135             start
136         ;;
137         "stop") 
138             stop
139         ;;
140         "unzip") 
141             #执行解压
142             shenniu_unzip
143             #执行启动
144             start
145         ;;
146         *) 
147             echo "${1}无任何操作"
148         ;;
149     esac
150 else
151     echo "
152     command如下命令:
153     unzip:解压并启动
154     start:启动
155     stop:停止进程
156     restart:重启
157 
158     示例命令如:./shenniu_publish start
159     "
160 fi

正如上面小节说的,shell中的参数 package-name,activeProfile,boot-main 都是由mvn中profiles的properties中提供,是可变的参数,脚本代码本身不需要人工去修改,只需要变的是mvn的参数即可;其实在我们生成zip包的时候,shell中的参数就被替换了,可以看zip中shell文件内容如:

ab1194ed8e01196634e39f915fa07e81.png

linux上使用shenniu_publish.sh启动程序

把生成的zip上传到linux上,通过命令解压:

1 unzip -od eureka-server-0.0.1-node eureka-server-0.0.1-node.zip

其实shell脚本中包含有解压命令,但是我在打包时放在了zip中,所以只能通过手动解压了,当然可以调整;此时进入加压目录如此:

c50fc3b80220bec519ccecaabc02d440.png

注:这里第一次执行./shenniu_publish.sh脚本时候,提示了错误信息;是由于我是在windows上编辑的这个脚本,其空格等和linux上不一样,所以运行会有问题,要解决可以使用vim命令在linux把该文件转成linux格式,如下命令:

1 vim shenniu_publish.sh
2 set ff=unix
3 :wq

执行完后,再来运行脚本./shenniu_publish.sh,此时有如下提示:

3a365962f22755fb9dbca3ed52372d08.png

此刻我们文件是解压状态,因此只需要start命令启动程序即可:

976bafd7735cf87389780fc098db48ff.png

到这里shenniu_publish.sh脚本使用就完成了,只要脚本没有提示错误,基本都能启动jar服务;其他restart和stop命令也如此执行就行:

a5a1b5e024017f78cae06de0968dffd8.png

可以去研究下shell代码,希望该脚本能给你带来效率和好的学习思路

欢迎工作一到五年的Java工程师朋友们加入Java程序员开发: 721575865

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot可以通过Java的ProcessBuilder类来执行shell脚本。具体步骤如下: 1. 创建ProcessBuilder对象,设置要执行shell命令或脚本文件路径。 2. 调用ProcessBuilder的start()方法启动进程,并获取进程的输入输出流。 3. 通过输入流向进程输入参数,通过输出流获取进程的输出结果。 4. 等待进程执行完毕,获取进程的退出状态。 示例代码如下: ```java String command = "/bin/sh /path/to/script.sh arg1 arg2"; ProcessBuilder pb = new ProcessBuilder(command.split(" ")); pb.redirectErrorStream(true); Process process = pb.start(); InputStream inputStream = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("Exit code: " + exitCode); ``` 其中,command变量为要执行shell命令或脚本文件路径,arg1和arg2为命令行参数。pb.redirectErrorStream(true)表示将进程的标准错误输出流和标准输出流合并为一个流。waitFor()方法会阻塞当前线程,直到进程执行完毕并返回退出状态。 ### 回答2: Spring Boot是一个流行的开源框架,它使得Spring应用程序的构建和部署变得更加简单和高效。对于需要在Spring Boot应用程序中执行shell脚本的任务,有几种不同的方法。 一种方法是使用Java中的Runtime类来执行shell脚本。Spring Boot提供了一个CommandLineRunner接口,您可以将其实现添加到应用程序中,这将允许您在应用程序启动时执行shell脚本。以下是一个简单的示例: ``` @Component public class ShellCommandExecutor implements CommandLineRunner { @Override public void run(String... args) throws Exception { String command = "sh /path/to/your/script.sh"; Runtime.getRuntime().exec(command); } } ``` 这个示例中,我们创建了一个名为ShellCommandExecutor的组件,并实现了CommandLineRunner接口。在run方法中,我们使用Runtime类来执行shell脚本。您需要将实际的脚本路径替换为“/path/to/your/script.sh”。 另一种方法是使用Java中的ProcessBuilder类。这个类提供了更多的控制和灵活性,允许您设置环境变量,重定向输入和输出等。以下是一个使用ProcessBuilder来执行shell脚本的简单示例: ``` @Component public class ShellCommandExecutor implements CommandLineRunner { @Override public void run(String... args) throws Exception { ProcessBuilder builder = new ProcessBuilder(); builder.command("sh", "/path/to/your/script.sh"); Process process = builder.start(); int exitCode = process.waitFor(); } } ``` 在这个示例中,我们创建了一个ProcessBuilder对象,并设置了要执行shell脚本的路径。然后我们调用start方法来启动进程,并使用waitFor方法来等待进程完成。您可以使用exitCode变量来获取进程的退出代码。 无论您选择哪种方法,请注意在执行shell脚本时要小心。请确保您只在必要情况下使用shell脚本,以避免潜在的安全漏洞。最好的做法是尽可能使用Java API来完成您需要的任务,而不是依赖于外部脚本。 ### 回答3: Spring Boot 是一个基于 Spring 框架的开发工具,它同时也提供了方便的集成和外部化配置方式。Spring Boot 提供了大量的 Web 依赖,可以轻松地开发 Web 应用程序。在实际的项目开发过程中,我们可能会需要执行 Shell 脚本。那么,如何在 Spring Boot 应用程序中执行 Shell 脚本呢? 一般来说,可以通过 Java 中的 Runtime 类执行 Shell 命令。在 Spring Boot 中,也可以使用 ProcessBuilder 类来执行 Shell 脚本。具体步骤如下: 1. 在 Maven 或 Gradle 中引入外部依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-exec</artifactId> <version>1.3</version> </dependency> ``` 2. 在 Controller 中编写代码: ```java @RestController public class ShellController { @GetMapping("/execute") public ResponseEntity<String> executeShellScript() throws IOException { String command = "/path/to/script.sh arg1 arg2"; // 设置 Shell 脚本的路径和参数 String output = runShellScript(command); return ResponseEntity.ok(output); } private String runShellScript(String command) throws IOException { DefaultExecutor executor= new DefaultExecutor(); executor.setWorkingDirectory(new File("/path/to/script/")); // 设置工作目录 executor.setStreamHandler(new PumpStreamHandler(System.out, System.err)); CommandLine cmdLine= CommandLine.parse(command); int exitValue= executor.execute(cmdLine); // 执行 Shell 脚本 return "Exit value: " + exitValue; // 返回输出结果 } } ``` 上述代码中,我们定义了一个 ShellController 类,其中包含了一个 executeShellScript() 方法,该方法用于执行 Shell 脚本。在方法中,我们指定了 Shell 脚本文件的路径和参数,并使用 runShellScript() 方法执行脚本。在该方法中,我们使用了 common-exec 提供的 DefaultExecutor 类来执行 Shell 脚本,并设置了工作目录和流处理器。执行完成后,我们返回 Shell 脚本的输出结果。 总之,使用 Spring Boot 执行 Shell 脚本的过程非常简单。只需要在 Controller 中编写相关代码即可。通过上述方法,我们可以轻松地在 Spring Boot 应用程序中执行 Shell 脚本,实现一些需要 Shell 命令才能完成的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值