Spring项目中@Service内配置嵌入式Jetty整合REST服务失败求助
解决Spring多服务项目中嵌入式Jetty集成CXF REST的问题
看起来你遇到的核心问题是Spring上下文加载冲突和CXF与现有Spring环境的关联方式错误。外部main方法能正常运行是因为它完全手动控制了上下文的创建和Jetty的启动顺序,但把逻辑放到Spring内部的@Service里时,就和项目已有的Spring上下文产生了重叠或割裂,导致请求找不到对应的处理观察者,甚至出现资源重复注册的情况。
我给你梳理下问题根源和具体解决方案:
问题根源分析
你在@Service里沿用了外部启动的代码,手动添加了ContextLoaderListener并指定了新的AnnotationConfigWebApplicationContext——这相当于在项目已有的Spring上下文之外,又创建了一个独立的Web上下文。两个上下文相互隔离,导致:
- REST服务的Bean可能注册到了新上下文里,但原项目的业务Bean在另一个上下文,请求处理时无法找到对应的观察者;
- 如果你在
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
相关产品推荐
相关产品推荐

