百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

class 增量发包改造为 jar 包方式发布

liuian 2025-07-09 14:16 3 浏览

大纲

  1. class 增量发包介绍
  2. 项目目录结构介绍
  3. jar 包方式发布落地方案


class 增量发包介绍

当前项目的迭代修复都是通过 class 增量包来发版本的

将改动的代码 class 增量打包,如下图

class 发包方式优点

  1. class 增量发布,增量包体积较小
  2. 出现问题时,可以本地打log编译后,临时替换对应 class,便于调试
  3. 可以方便的看出本地迭代包文件变动情况 (用户不太关心)


但是也存在一些问题,开发人员维护困难,主要体现在以下几个点

  1. 每次编译后需要开发人员根据变动记录,手动收集本次迭代变动 class,容易出现错漏
  2. 本地打包后,一个 class可能会生成 n 个 class 文件 (FileToolsUI$1.class,FileToolsUI$2.class); ( 在 idea 中是看不出来的,必须在目录下才能看到) 导致增量包经常出问题...
  3. 经常要维护一个稳定版本的全量基线包
  4. 由于是 class 增量升级,误打包或重构删除的类,客户那边依旧会冗余,不利于重构; (而当前项目代码臃肿,项目亟需重构 很多java文件代码量的比较大 3k,5k,7k代码; )

于是大家商量一下想改变升级包提供方式,通过提供全量可 jar 包升级

项目目录结构介绍

项目工程结构如下

KingDomFileToolCombine
	java 源代码
	resources  资源目录1
	source   资源目录 2
	doc  文档
	lib 外部依赖 jar 包存放目录

由于早期项目没有使用构建工具,当初导入项目也是花了些时间;

具体可以查看 idea 导入并配置非标准maven工程


jar 包方式发布落地方案

改造后要求满足以下需求

  1. 当前项目 jar包形式发布
  2. 外部依赖单独存放在 lib目录下 (减少升级包体积)
  3. 配置文件单独存放在jar包的同级目录的bin目录下 (方便用户调整配置)


使用 maven 打 jar'包方案实现步骤如下

  1. 添加 pom.xml 使用 maven 管理依赖
  2. 使用 maven <systemPath>管理本地 jar 包
  3. 选择maven构建插件,打 jar 包
  4. 刷新 maven 依赖; (最好是手动删除 project structure中的依赖,然后刷新maven)
  5. mvn clean package 打 jar 包
  6. cd 到目录下 java -jar xxx.jar 启动应用


pom,xml 配置如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.szkingdom.filetool</groupId>
    <artifactId>KingDomFileToolCombine</artifactId>
    <version>V3.0.0</version>

    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>7</maven.compiler.source>
        <maven.compiler.target>7</maven.compiler.target>
        <!--  Java版本  -->
        <java.version>1.7</java.version>
        <!--    通过${hutool.version}来使用    -->
        <spring.version>3.2.2.RELEASE</spring.version>
    </properties>

<dependencies>
     <!-- 使用 maven <systemPath>管理本地 jar 包
          项目依赖的外部jar 是放在/lib目录下 (有的jar存在多版本)
          - 1 <scope>system</scope> 
					- 2 <systemPath>${project.basedir}/lib/dom4j-1.6.1.jar</systemPath>
					- 3 实在不知道 groupId 的用了自定义值替换; 比如local
					- 4 在maven-dependency-plugin 打包到 lib 目录时,会改变jar名称为 (artifactId-version.jar)
					- 5 配置完成后重新刷新 maven 依赖 (idea 中建议先手动移除 
          project structure>modules>dependencies 中的依赖,刷新后maven会自动配置)
     -->
    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.6.1</version>
        <!--system,类似provided,需要显式提供依赖的jar以后,Maven就不会在Repository中查找它-->
        <scope>system</scope>
        <systemPath>${project.basedir}/lib/dom4j-1.6.1.jar</systemPath>
    </dependency>
    <dependency>
        <groupId>bouncycastle</groupId>
        <artifactId>bcprov-jdk15</artifactId>
        <!--
						在maven-dependency-plugin 打包到 lib 目录时,会改变 jar 名称为 (artifactId-version.jar; )
            将原 jar包数字拆分到 <version>;可以实现重新打包后名称不变 如: bcprov-jdk15-133.jar
        -->
        <version>133</version>
        <scope>system</scope>
        <systemPath>${project.basedir}/lib/bcprov-jdk15-133.jar</systemPath>
    </dependency>
    <dependency>
        <!--实在不知道 groupId 的用了自定义值替换; 比如local-->    
        <groupId>local</groupId>
        <artifactId>chinapnr</artifactId>
        <!--实在不知道 version 的用了自定义值替换; 比如localversion; 
            在maven-dependency-plugin 打包到 lib 目录时,
              会改变 jar 名称为 (artifactId-version.jar;如: chinapnr-localversion.jar )
            需要配合 maven-jar-plugin <Class-Path>标签一起使用, 
              配置的 class-path jar名称为 chinapnr-localversion.jar
        -->    
        <version>localversion</version>
        <scope>system</scope>
        <systemPath>${project.basedir}/lib/chinapnr.jar</systemPath>
    </dependency>
   
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
        <scope>system</scope>
        <systemPath>${project.basedir}/lib/spring-beans-3.2.2.RELEASE.jar</systemPath>
    </dependency>
    
</dependencies>


<build>
        <!--构建后 jar 文件名称-->
        <finalName>kingDomFileToolCombine</finalName>
        <!--java 源代码所在目录 默认 src/main/java-->
        <sourceDirectory>java</sourceDirectory>
        <!--配置文件所在目录 默认 src/main/resources-->
        <scriptSourceDirectory>source</scriptSourceDirectory>
        <!--<!–构建目录 默认target–>-->
        <directory>bin</directory>
        <!--编译后class存放目录 默认target/classes-->
        <outputDirectory>bin</outputDirectory>
        <!--资源文件夹,可配置多个-->
        <resources>
            <resource>
                <directory>resources</directory>
            </resource>
            <resource>
                <directory>source</directory>
            </resource>
        </resources>


        <!--插件打包-->
        <plugins>
            <!--在打包阶段将依赖的jar包导出到lib目录下-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <type>jar</type>
                            <includeTypes>jar</includeTypes>
                            <outputDirectory>out/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <archive>
                        <!-- 生成MANIFEST.MF的设置 -->
                        <manifest>
                            <useUniqueVersions>false</useUniqueVersions>
                            <!-- jar启动入口类 -->
                            <mainClass>com.szkingdom.FileTools.UI.FileToolsSurface</mainClass>
                            <!-- 为依赖包添加路径, 这些路径会写在MANIFEST文件的Class-Path下 -->
                            <addClasspath>true</addClasspath>
                        </manifest>

                        <manifestEntries>
                            <!--将依赖.jar  写进MANIFEST.MF文件中的Class-Path-->
                            <Class-Path>lib/bcprov-jdk15-133.jar  lib/cipher-localversion.jar</Class-Path>
                        </manifestEntries>
                    </archive>
                    <!-- 指定打包后 jar包的位置,设置为根目录下 /out -->
                    <outputDirectory>out</outputDirectory>
                    <excludes>
                        <exclude>*.jar</exclude> <!--排除打包后的 jar文件本身-->
                    </excludes>
                </configuration>
            </plugin>

        </plugins>

</build>
</project>




打包启动 jar 后报错记录解决

mvn clean package 打包 后 cd 到 jar 所在目录 java -jar 启动程序

#### Error assembling JAR: A zip file cannot include itself 
- 装配JAR错误:zip文件不能包含自身
 ```asp
<excludes>   
    <exclude>*.jar</exclude> <!--排除打包后的 jar文件本身-->
</excludes>
```

#### java -jar 运行程序报错, java.lang.NoClassDefFoundError
- java.lang.NoClassDefFoundError 找不到外部依赖的 jar 
- 解决: 
    - 1 打包时插件配置 <Class-Path>
    - 2 需要将 lib 目录放到 jar同级别目录
    
#### java -jar 运行程序报错, java.lang.Error: Properties init: Could not determine current working directory.
- 原因: 找不到当前所在目录; 每次重新 mvn clear package 时 ,旧的命令行窗口所在目录已经被清除了
- 解决: 重新 cd 到 jar 目录 运行 java -jar
    


代码改造,之前读取 classpath 下的配置,改造为从 jar 包外文件中读取

//编写配置文件加载工具类 
public class ConfigFileUtil {
    /**
     * 文件分割路径 ,mac windows 适配
     */
    public final static String PATH_SPLIT = File.separator;
    private static String CONFIG_FILE_PATH;

    static {
        //System.out.println(" 相对于当前用户目录的相对路径 user.dir :" + System.getProperty("user.dir"));
        //获取当前 jar 包路径  .....jar
        String jarFilePath = FileUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        System.out.println(" jar文件所在路径为 :" + jarFilePath);
        try {
            jarFilePath=URLDecoder.decode(jarFilePath, "utf-8");// 转化为utf-8编码,支持中文
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        File file = new File(jarFilePath);
        CONFIG_FILE_PATH = file.getParent();
        System.out.println(" 配置文件所在路径为 :" + CONFIG_FILE_PATH);
    }

    public static String getFileAbsolutePath(String underBinPath) {
        String filePath = "";
        if (underBinPath.startsWith("bin")) {
            filePath = FileUtil.CONFIG_FILE_PATH + FileUtil.PATH_SPLIT + underBinPath;
        } else {
            filePath = FileUtil.CONFIG_FILE_PATH + FileUtil.PATH_SPLIT + "bin" + FileUtil.PATH_SPLIT + underBinPath;
        }
        System.out.println(" 配置文件所在绝对路径为 :" + filePath);
        return filePath;
    }

    /**
     * @param underBinPath 存放在 /src/main/resources/bin 下的相对路径
     * @return
     */
    public static FileInputStream getConfigFileInputStream(String underBinPath) {
        FileInputStream is = null;
        try {
            String fileAbsolutePath = getFileAbsolutePath(underBinPath);
            is = new FileInputStream(fileAbsolutePath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return is;
    }

    public static FileOutputStream getConfigFileOutPutStream(String underBinPath) {
        FileOutputStream os = null;
        try {
            String fileAbsolutePath = getFileAbsolutePath(underBinPath);
            os = new FileOutputStream(fileAbsolutePath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return os;
    }


项目问题每天不重样,遇到问题解决问题, 调整升级方式为后续代码重构做铺垫

相关推荐

使用Assembly打包和部署Spring Boot工程

SpringBoot项目的2种部署方式目前来说,SpringBoot项目有如下2种常见的部署方式一种是使用docker容器去部署。将SpringBoot的应用构建成一个docke...

java高级用法之:调用本地方法的利器JNA

简介JAVA是可以调用本地方法的,官方提供的调用方式叫做JNI,全称叫做javanativeinterface。要想使用JNI,我们需要在JAVA代码中定义native方法,然后通过javah命令...

Linux中如何通过Shell脚本来控制Spring Boot的Jar包启停服务?

SpringBoot项目在为开发者带来方便的同时,也带来了一个新的问题就是Jar包如何启动?在一般情况下我们都是采用了最为经典的java-jar命令来进行启动。然后通过ps命令找到对应的应用线程通...

牛逼!自己手写一个热加载(人民币手写符号一个横还是两个横)

热加载:在不停止程序运行的情况下,对类(对象)的动态替换JavaClassLoader简述Java中的类从被加载到内存中到卸载出内存为止,一共经历了七个阶段:加载、验证、准备、解析、初始化、使用、...

java 错误: 找不到或无法加载主类?看看怎么解决吧!

问题扫述:项目名称调整,由原来的com.mp.qms.report.biz调整为com.mp.busicen.mec.qms.report.biz后。项目在IDEA直接运行,但打包部署到服务器...

如何将 Spring Boot 工程打包成独立的可执行 JAR 包

导语:通过将SpringBoot项目打包成独立的可执行JAR包,可以方便地在任何支持Java环境的机器上运行项目。本文将详细介绍如何通过Maven构建插件将SpringBoot...

class 增量发包改造为 jar 包方式发布

大纲class增量发包介绍项目目录结构介绍jar包方式发布落地方案class增量发包介绍当前项目的迭代修复都是通过class增量包来发版本的将改动的代码class增量打包,如下图cla...

Jar启动和IDE里启动Sprintboot的区别

想聊明白这个问题,需要补充一些前提条件,比如Fatjar、类加载机制等1、Fatjar我们在开发业务程序的时候,经常需要引用第三方的jar包,最终程序开发完成之后,通过打包程序,会把自己的代码和三...

Java 20年,以后将往哪儿走?(java还能流行多久)

在今年的Java20周年的庆祝大会中,JavaOne2015的中心议题是“Java的20年”。甲骨文公司Java平台软件开发部的副总裁GeorgesSaab的主题演讲就将关注点放在了java...

Spring Boot Jar 包秒变 Docker 镜像实现多环境部署

你是否在互联网大厂后端开发工作中,遇到过这样的困扰?当完成一个SpringBoot项目开发,准备将Jar包部署到不同环境时,却发现各个环境依赖不同、配置复杂,部署过程繁琐又容易出错,不仅耗费...

从0开始,让你的Spring Boot项目跑在Linux服务器

1搭建Linux服务器1.1购买阿里云服务器或安装虚拟机这里建议是CentOS7.X或CentOS8.X,当然其他的Linux如deepin、Ubuntu也可以,只是软件环境的安装包和安装方式...

【技术】Maven 上传第三方jar包到私服

通过nexus后台上传私服以NexusRepositoryManagerOSS2.14.5-02为例。登录nexus后台。定义Maven坐标Maven坐标有两种方式:1.自定义参数;2....

JVM参数、main方法的args参数使用

一、前言我们知道JVM参数分为自定义参数、JVM系统参数,Javamain方法的参数。今天就谈谈怎么使用吧。二、查看jvm参数定义自定义参数我们打开cmd窗口,输入java,就能看到自定义参数的格式...

Maven项目如何发布jar包到Nexus私服

Maven项目发布jar包到Nexus私服在编码过程中,有些通用的代码模块,有时候我们不想通过复制粘贴来粗暴地复用。因为这样不仅体现不了变化,也不利于统一管理。这里我们使用mavendeploy的方...

干货丨Hadoop安装步骤!详解各目录内容及作用

Hadoop是Apache基金会面向全球开源的产品之一,任何用户都可以从ApacheHadoop官网下载使用。今天,播妞将以编写时较为稳定的Hadoop2.7.4版本为例,详细讲解Hadoop的安...