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

如何实现仅在依赖模块加载时运行的Java代码?

模块化3D模型处理库实现方案(基于SPI机制)

核心设计思路

采用Java原生的**服务提供者接口(SPI)**实现核心库与模型处理器模块的完全解耦:核心库仅定义统一接口,各3D模型类型的处理逻辑封装为独立模块(如dmal-dae),核心库通过SPI动态发现并加载可用的处理器,无需硬编码依赖关系。


分步实现

1. 核心库(dmal-core)定义基础接口与异常

首先在核心库中定义所有处理器必须实现的接口,以及自定义异常类:

统一处理器接口

// dmal-core 核心接口
public interface ModelProcessor {
    // 返回当前处理器支持的文件后缀(不带前缀点)
    String supportedExtension();
    // 执行模型文件处理逻辑
    void process(InputStream inputStream);
}

自定义异常类

// dmal-core 自定义异常
public class ModelProcessorNotFoundException extends RuntimeException {
    public ModelProcessorNotFoundException(String extension) {
        super("未找到支持." + extension + "格式的处理器模块,请确认已添加对应依赖");
    }
}

2. 核心库实现动态加载与统一入口

Dmal类通过SPI自动加载所有可用的ModelProcessor实现,根据文件后缀匹配处理器:

// dmal-core 核心入口类
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;

public class Dmal {
    private final Map<String, ModelProcessor> processorCache;

    public Dmal() {
        processorCache = new HashMap<>();
        // 通过SPI加载所有ModelProcessor实现并缓存
        ServiceLoader<ModelProcessor> loader = ServiceLoader.load(ModelProcessor.class);
        for (ModelProcessor processor : loader) {
            processorCache.put(processor.supportedExtension().toLowerCase(), processor);
        }
    }

    public void process(String fileName) {
        String fileExtension = extractFileExtension(fileName).toLowerCase();
        InputStream inputStream = loadFileToStream(fileName);

        ModelProcessor processor = processorCache.get(fileExtension);
        if (processor == null) {
            throw new ModelProcessorNotFoundException(fileExtension);
        }

        try {
            processor.process(inputStream);
        } finally {
            // 确保输入流关闭
            try {
                inputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 提取文件后缀
    private String extractFileExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
            throw new IllegalArgumentException("无效文件名:" + fileName);
        }
        return fileName.substring(lastDotIndex + 1);
    }

    // 文件转输入流的实现(可根据实际场景调整,如本地文件、资源文件等)
    private InputStream loadFileToStream(String fileName) {
        try {
            return getClass().getClassLoader().getResourceAsStream(fileName);
        } catch (Exception e) {
            throw new RuntimeException("文件加载失败:" + fileName, e);
        }
    }
}

3. 独立处理器模块实现(以dmal-dae为例)

在dmal-dae模块中实现ModelProcessor接口,并配置SPI元数据:

Collada处理器实现

// dmal-dae 模块中的处理器
import java.io.InputStream;

public class ColladaProcessor implements ModelProcessor {
    @Override
    public String supportedExtension() {
        return "dae";
    }

    @Override
    public void process(InputStream inputStream) {
        // 此处编写DAE文件的具体解析与处理逻辑
        System.out.println("开始处理DAE模型文件...");
        // 调用Collada解析库的代码写在这里
    }
}

SPI配置

在dmal-dae模块的resources/META-INF/services目录下创建文件,文件名是ModelProcessor接口的全类名(如com.example.dmal.core.ModelProcessor),文件内容为处理器类的全类名:

com.example.dmal.dae.ColladaProcessor

方案优势

  • 完全解耦:核心库不依赖任何处理器模块,新增模型类型仅需添加独立模块,无需修改核心代码
  • 轻量级:基于Java原生SPI机制,无需引入额外依赖
  • 动态发现:处理器模块在运行时自动被加载,无需手动注册
  • 异常清晰:依赖缺失时抛出明确的自定义异常,便于排查问题

内容的提问来源于stack exchange,提问作者Jordan Ellison

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:02:33