Maven分离lib打包,lib包自动同步,加速项目部署
- 目标
- 整体步骤
- Maven配置
- 1. 分离打包:配置打包、将依赖jar拷贝到外部
- 2. 编辑MANIFEST.MF
- 本地<=>服务器lib快速同步
- 1. 使用前提
- 2. 实现同步
目标
- 每次部署只打包项目本身代码,这样部署会很快,因为包非常小。
- 对于依赖的jar包,只有在需要更新时(pom变动时)单独上传到服务器。
整体步骤
分为两步:
- 将项目代码和依赖包分开打包,每次只发布项目代码的jar(依赖Jenkins,或者手动拷贝到服务器中)
- 每次修改pom依赖后,通过脚本同步一次lib包中的jar到服务器
Maven配置
这一块比较简单,主要目的是为了将项目依赖的jar和项目本身代码分开打包
1. 分离打包:配置打包、将依赖jar拷贝到外部
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<!--这里是为了将依赖拷贝出来,不打包到项目代码的jar中-->
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!--存放依赖jar的文件位置,这里配置成在target/lib下-->
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<!--不拷贝间接依赖的jar,这里配置成false,表示拷贝间接依赖-->
<excludeTransitive>false</excludeTransitive>
<!--去掉依赖jar的版本号,这里不去掉,方便jar的更新同步-->
<stripVersion>false</stripVersion>
<!--包含jar的scope范围,此处设置为compile,打击可以根据需要调整-->
<includeScope>compile</includeScope>
</configuration>
</execution>
</executions>
</plugin>
2. 编辑MANIFEST.MF
这个文件在项目代码打完包的META-INF/MANIFEST.MF。作用是记录jar的Main入口类和所依赖的jar的位置。可以通过解压打完包的jar查看。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<!--主要是为了向添加MANIFEST.MF中添加必要的内容,如下-->
<manifest>
<mainClass>com.xxx.xxx.Application</mainClass>
<!-- 入口程序 -->
<addClasspath>true</addClasspath>
<!-- 添加依赖jar路径,这个大家解压打包后的项目jar, 可以观察一下MANIFEST.MF文件内容就明白了 -->
<!-- 自己动手丰衣足食,实践出真知 -->
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
本地<=>服务器lib快速同步
1. 使用前提
- 使用物理服务器部署项目的同学,为了方便在开发阶段快速部署可以参考。
- 对于使用k8s等方式部署的项目,还得找运维同学配置。
- 这个方式主要是我自己开发阶段为了快速部署写的一点代码,主要是java实现。
2. 实现同步
所谓的快速同步,其实就是通过代码自动ssh到服务器上,获取服务器上的jar列表,和本地的jar列表进行比较,将新增的jar拷贝到服务器上,并将服务器上过期的jar删掉的过程。(这里使用Java,基于jsch实现,直接上代码)
- 首选引入依赖(因为我只在本地使用,所以scope配置成test)
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
<scope>test</scope>
</dependency>
- 代码实现
这个代码比较简单,我也做了注释,大家直接看一下吧。
【注意】:要本地自己先maven package打个包再运行以下代码上传
package sync_lib;
import cn.hutool.core.io.FileUtil;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author xchen
*/
public class SyncLib {
private static Session session;
private static ChannelSftp channelSftp;
//只打印日志,不做上传删除操作(debug用)
private static final Boolean onlyPrint = true;
public static void main(String[] args) throws Exception {
//初始化ssh连接
initChannel();
try {
//cd 到服务器上的jar包所在目录
channelSftp.cd("服务器的lib目录(jar所在目录)");
//将jar目录下的jar都ls出来,保存到oldJarList中
Vector ls = channelSftp.ls(".");
List<String> oldJarList = new ArrayList<>();
for (int i = 0; i < ls.size(); i++) {
ChannelSftp.LsEntry o = (ChannelSftp.LsEntry) ls.get(i);
String filename = o.getFilename();
if (filename.endsWith(".jar")) {
oldJarList.add(filename);
}
}
//这个是intellij idea中分离打包后的lib的路径, 大家可以直接改成自己本地的绝对路径
String newLibPath = SystemUtil.get(SystemUtil.USER_DIR) + "/target/lib/";
//获取本地最新jar的列表
List<String> newLibList = FileUtil.listFileNames(newLibPath);
//对比新老jar列表,找出要新增的jar,删除的jar
List<String> addJarList = addJarList(oldJarList, newLibList);
List<String> removeJarList = removeJarList(oldJarList, newLibList);
//上传新增的jar
for (String addJarName : addJarList) {
if (onlyPrint) {
channelSftp.put(newLibPath + addJarName, addJarName);
}
System.out.println("add jar ==> " + addJarName);
}
//删除过期的jar
for (String removeJarName : removeJarList) {
if (onlyPrint) {
channelSftp.rm(removeJarName);
}
System.out.println("remove jar ==> " + removeJarName);
}
} finally {
//关闭ssh连接
closeChannel();
}
}
public static List<String> removeJarList(List<String> oldLibList, List<String> newLibList) {
Set<String> newLibSet = new HashSet<>(newLibList);
return oldLibList.stream().filter(item -> !newLibSet.contains(item)).collect(Collectors.toList());
}
public static List<String> addJarList(List<String> oldLibList, List<String> newLibList) {
Set<String> oldLigSet = new HashSet<>(oldLibList);
return newLibList.stream().filter(item -> !oldLigSet.contains(item)).collect(Collectors.toList());
}
public static void initChannel() throws JSchException {
//声明JSCH对象
JSch jSch = new JSch();
//获取一个Linux会话
session = jSch.getSession("root", "服务器IP", 22);
//设置登录密码
session.setPassword("服务器密码");
//关闭key的检验
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
session.setConfig(sshConfig);
//连接Linux
session.connect();
//通过sftp的方式连接
channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
}
private static void closeChannel() {
if (channelSftp != null) {
channelSftp.disconnect();
}
if (session != null) {
session.disconnect();
}
}
}