You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Liquibase的customChange时出现ClassNotFoundException异常

问题解决:Liquibase CustomChange 类找不到异常 + 后续运行Node.js脚本方案

一、ClassNotFoundException 原因与修复

你遇到的com.example.RunCustomCommand找不到的核心问题是Java类的包结构与实际文件目录不匹配。Java要求包名对应文件系统的目录结构,你的代码声明了package com.example;,但文件直接放在根目录下,编译后的类文件没有被正确组织到com/example目录中,导致Liquibase无法从Jar包中找到该类。

修复步骤:

  1. 调整本地文件目录结构
    在项目根目录创建com/example子目录,将RunCustomCommand.java移动到该目录下:

    项目根目录
    ├── com
    │   └── example
    │       └── RunCustomCommand.java
    ├── changelog.xml
    ├── Dockerfile
    └── docker-compose.yml
    
  2. 修改Dockerfile编译逻辑
    更新Dockerfile,确保编译时识别包目录,并将带目录结构的类文件打包进Jar:

    FROM liquibase:latest
    
    WORKDIR /node-app
    USER root
    COPY . .
    RUN apt update -y
    # 安装JDK和Node.js(提前安装方便后续运行Node脚本)
    RUN apt install default-jdk nodejs npm -y
    # 编译带包结构的Java类,-d 指定编译后类文件输出目录
    RUN javac -cp /liquibase/internal/lib/liquibase-core.jar -d . com/example/RunCustomCommand.java
    # 打包时包含完整目录结构
    RUN jar cvf run-custom-command.jar com/
    # 复制到Liquibase lib目录
    RUN cp /node-app/run-custom-command.jar /liquibase/lib/run-custom-command.jar
    
    CMD [ "sh" ]
    
  3. 验证Jar包结构(可选)
    可以在Dockerfile中加一步验证命令,确保Jar包包含正确的目录:

    RUN jar tf run-custom-command.jar
    

    输出应该包含com/example/RunCustomCommand.class。

  4. 调整docker-compose命令(可选)
    因为已经把Jar包复制到/liquibase/lib,Liquibase会自动加载该目录下的Jar,所以可以去掉--classpath参数,简化命令:

    command:
      - |
        ls
        liquibase update --changelog-file=changelog.xml --username=postgres --password=postgres --url=jdbc:postgresql://db:5432/postgres
    

二、在自定义类中运行Node.js脚本

修改RunCustomCommand.java的execute方法,使用ProcessBuilder调用Node命令执行脚本:

package com.example;

import liquibase.change.custom.*;
import liquibase.database.Database;
import liquibase.exception.CustomChangeException;
import liquibase.exception.SetupException;
import liquibase.exception.ValidationErrors;
import liquibase.resource.ResourceAccessor;
import java.io.IOException;

public class RunCustomCommand implements CustomTaskChange {

    private ResourceAccessor resourceAccessor;

    @Override
    public void execute(Database database) throws CustomChangeException {
        // 示例:运行当前目录下的test.js脚本
        ProcessBuilder pb = new ProcessBuilder("node", "/node-app/test.js");
        try {
            Process process = pb.start();
            // 等待脚本执行完成
            int exitCode = process.waitFor();
            System.out.println("Node脚本执行完成,退出码:" + exitCode);
        } catch (IOException | InterruptedException e) {
            throw new CustomChangeException("执行Node脚本失败", e);
        }
    }

    @Override
    public String getConfirmationMessage() {
        return "Custom task executed successfully.";
    }

    @Override
    public void setUp() throws SetupException {
        // 初始化逻辑
    }

    @Override
    public void setFileOpener(ResourceAccessor resourceAccessor) {
        this.resourceAccessor = resourceAccessor;
    }

    @Override
    public ValidationErrors validate(Database database) {
        return new ValidationErrors();
    }
}

注意事项:

  • 确保Dockerfile中已经安装了Node.js(上面的Dockerfile已经包含apt install nodejs npm -y)
  • 将你的Node.js脚本(比如test.js)放在项目根目录,会被COPY到容器的/node-app目录下
  • 如果需要传递参数给Node脚本,可以在ProcessBuilder的参数列表中添加,比如new ProcessBuilder("node", "/node-app/test.js", "param1", "param2")

内容的提问来源于stack exchange,提问作者Nguyễn Sỹ Tùng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:09:52