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

如何让Eclipse LSP4e服务单实例化?避免新建Java文件重初始化

问题解决:Eclipse LSP4e语言服务重复初始化问题

核心问题分析

配置singleton="true"后仍出现重复初始化,根源在于:

  1. LSP4e框架通过反射实例化CodecompProcessStreamConnectionProvider,不会调用你自定义的getInstance()方法,所以手写单例逻辑无效。
  2. 构造函数直接调用init(),哪怕框架创建临时实例(singleton生效前的冗余操作)也会触发初始化。
  3. ProcessStreamConnectionProvider的start()方法可能被多次调用,导致重复启动服务进程。

修复方案

1. 确认LSP4e的Singleton配置有效性

你已在plugin.xml中设置singleton="true",需额外检查:

  • 服务器ID唯一,无重复定义的同ID服务
  • contentTypeMapping仅关联到该服务ID,未映射其他服务

2. 重构连接提供者的初始化逻辑

修改CodecompProcessStreamConnectionProvider,让初始化逻辑全局仅执行一次,适配LSP4e的实例化机制:

public class CodecompProcessStreamConnectionProvider extends ProcessStreamConnectionProvider {
    // volatile保证多线程下初始化状态的可见性
    private static volatile boolean globalInitialized = false;
    private static final Object initLock = new Object();
    private static final long INIT_SERVER_TIMEOUT_SECONDS = 180;

    // 空构造函数,避免实例创建时触发重复初始化
    public CodecompProcessStreamConnectionProvider() {
    }

    @Override
    public void start() throws IOException {
        // 双重检查锁,确保全局仅初始化一次
        if (!globalInitialized) {
            synchronized (initLock) {
                if (!globalInitialized) {
                    init();
                    globalInitialized = true;
                }
            }
        }
        // 检查命令是否已设置,避免重复调用super.start()启动多个进程
        if (getCommands() == null || getCommands().isEmpty()) {
            super.start();
        }
    }

    private void init() {
        Logger.debug("Initializing chat server asynchronously");

        try {
            AsyncExecutor.executeWithTimeout(() -> {
                try {
                    CodecompLocator locator = new CodecompLocator();
                    List<String> commands = new ArrayList<>();
                    String CodecompAgentFolderPath = locator.findAgent().toFile().getParent();
                    Logger.debug("Codecomp agent location: " + CodecompAgentFolderPath);
                    File file = new File(CodecompAgentFolderPath + "/node");
                    file.setReadable(true);
                    file.setExecutable(true);
                    commands.add(CodecompAgentFolderPath + "/node");
                    commands.add("language-server.js");
                    commands.add("--stdio");
                    this.setCommands(commands);

                    this.setWorkingDirectory(CodecompAgentFolderPath);
                    Logger.debug("Chat server initialized successfully");
                } catch (Exception e) {
                    Logger.error(e, Messages.CodecompProcessStreamConnectionProvider_ErrorStartingChatLanguageServer);
                    throw new RuntimeException("Error initializing chat server", e);
                }
            }, INIT_SERVER_TIMEOUT_SECONDS, TimeUnit.SECONDS);
        } catch (TimeoutException | ExecutionException | InterruptedException e) {
            Logger.error(e, Messages.CodecompProcessStreamConnectionProvider_ErrorStartingChatLanguageServer);
        }
    }

    // 保留原有方法实现
    protected ProcessBuilder createProcessBuilder() {
        ProcessBuilder builder = super.createProcessBuilder();
        builder.environment().put("Codecomp_AGENT_LOGMESSAGE", "true");

        Map<String, String> proxySettings = CodecompProxyUtil.getProxyVars();
        proxySettings.forEach(builder.environment()::put);

        return builder;
    }

    public Object getInitializationOptions(URI rootUri) {
        CodecompInitializationOptions options = CodecompManager.getInstance().createInitializationOptions();
        return options;
    }

    public void handleMessage(Message message, LanguageServer languageServer, URI rootURI) {
        super.handleMessage(message, languageServer, rootURI);
    }
}

3. 排查服务意外关闭的触发点

检查是否存在以下导致服务shutdown的逻辑:

  • 是否监听文件关闭事件时主动调用服务shutdown方法
  • 客户端实现codecompChatLanguageClientImpl中是否有异常触发服务关闭的逻辑

关键调整说明

  • 移除自定义单例实例,改用全局初始化标记+双重检查锁,适配LSP4e的反射实例化机制
  • 将初始化逻辑从构造函数移到start()方法,确保服务真正启动时才执行初始化
  • 增加命令存在性检查,避免多次调用super.start()启动多个进程
  • 保留LSP4e原生singleton="true"配置,让框架负责管理服务实例的全局唯一性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 21:18:20