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

Spring项目中@Service内配置嵌入式Jetty整合REST服务失败求助

解决Spring多服务项目中嵌入式Jetty集成CXF REST的问题

看起来你遇到的核心问题是Spring上下文加载冲突和CXF与现有Spring环境的关联方式错误。外部main方法能正常运行是因为它完全手动控制了上下文的创建和Jetty的启动顺序,但把逻辑放到Spring内部的@Service里时,就和项目已有的Spring上下文产生了重叠或割裂,导致请求找不到对应的处理观察者,甚至出现资源重复注册的情况。

我给你梳理下问题根源和具体解决方案:

问题根源分析

你在@Service里沿用了外部启动的代码,手动添加了ContextLoaderListener并指定了新的AnnotationConfigWebApplicationContext——这相当于在项目已有的Spring上下文之外,又创建了一个独立的Web上下文。两个上下文相互隔离,导致:

  1. REST服务的Bean可能注册到了新上下文里,但原项目的业务Bean在另一个上下文,请求处理时无法找到对应的观察者;
  2. 如果你在applicationContext.xml里再引入REST类,这些Bean会在原上下文重复注册,引发冲突。

解决方案:复用现有Spring上下文

核心思路是让CXF直接使用项目已有的Spring上下文,不要再手动创建新的上下文。具体步骤如下:

1. 修改Service中的Jetty初始化逻辑

去掉手动创建上下文的代码,改用SpringBus关联CXF和现有Spring环境:

@Service
public class JettyHostService {

    @Autowired
    private ApplicationContext applicationContext;

    private Server jettyServer;

    // 确保在Spring上下文完全初始化后启动Jetty
    @PostConstruct
    public void startJetty() throws Exception {
        jettyServer = new Server(8888);

        // 配置CXF Servlet
        ServletHolder cxfServletHolder = new ServletHolder(new CXFServlet());
        ServletContextHandler contextHandler = new ServletContextHandler();
        contextHandler.setContextPath("/");
        contextHandler.addServlet(cxfServletHolder, "/rest/*");

        // 关键:让CXF复用现有Spring上下文
        SpringBus springBus = new SpringBus();
        springBus.setApplicationContext(applicationContext);
        BusFactory.setDefaultBus(springBus);

        jettyServer.setHandler(contextHandler);
        // 用异步线程启动Jetty,避免阻塞Spring上下文加载
        new Thread(() -> {
            try {
                jettyServer.start();
                jettyServer.join();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    // 可选:添加停止Jetty的方法
    @PreDestroy
    public void stopJetty() throws Exception {
        if (jettyServer != null && jettyServer.isStarted()) {
            jettyServer.stop();
        }
    }
}

2. 确保REST服务Bean在现有上下文注册

把你的REST服务类(比如PeopleApi这类端点)和配置类(AppConfig)通过Spring的常规方式注册到现有上下文:

  • 如果用注解驱动,在AppConfig上添加@ComponentScan扫描REST包,或者直接给REST类加@Service/@Component;
  • 如果用XML配置,在applicationContext.xml中引入这些类,但不要重复配置CXF相关的上下文参数。

3. 关键注意点

  • 不要在Spring Bean的初始化方法里直接调用server.join(),这个方法是阻塞的,会导致Spring上下文加载卡住;
  • 确保SpringBus正确关联了现有上下文,这样CXF才能找到注册的REST端点Bean;
  • 移除所有手动创建ContextLoaderListener和新Web上下文的代码,彻底复用现有环境。

这样调整后,Jetty启动时会直接使用项目原有的Spring上下文,既不会出现上下文隔离导致的观察者找不到问题,也不会引发资源重复注册的冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:19:33