0

0

嵌入式Jetty、Jersey与Weld CDI集成指南

DDD

DDD

发布时间:2025-10-23 11:24:02

|

284人浏览过

|

来源于php中文网

原创

嵌入式Jetty、Jersey与Weld CDI集成指南

本文详细介绍了如何在java se环境中,利用嵌入式jetty服务器、jersey框架和weld cdi实现一个功能完备的restful应用。文章聚焦于正确的依赖配置和weld cdi与jetty servlet容器的集成方式,旨在解决常见的依赖注入问题,确保cdi bean能够被正确发现和管理,从而构建一个稳定高效的独立rest服务。

构建嵌入式Jetty、Jersey与Weld CDI的RESTful应用

在Java生态中,构建一个轻量级、独立的RESTful服务是常见的需求。结合嵌入式Jetty作为Web服务器、Jersey作为JAX-RS实现以及Weld作为CDI(Contexts and Dependency Injection)容器,可以实现一个功能强大且易于部署的解决方案。然而,正确地集成这三者,尤其是确保CDI的依赖注入机制正常工作,常常是开发者面临的挑战。本文将提供一套经过验证的集成方案,帮助您顺利搭建此类应用。

1. 项目依赖配置

首先,正确配置项目的依赖是成功的关键。以下是一个推荐的Gradle配置,它包含了Jetty、Jersey和Weld集成所需的核心库。请注意,我们依赖于这些库的传递性依赖来引入其他必要的组件。

plugins {
    id 'application'
    id 'java'
    id 'eclipse' // 可选,如果使用Eclipse
}

repositories {
    mavenCentral()
}

dependencies {
    // 日志框架
    implementation 'org.slf4j:slf4j-api:2.0.4'
    implementation 'ch.qos.logback:logback-classic:1.4.5'

    // Jetty 服务器核心与Servlet支持
    implementation 'org.eclipse.jetty:jetty-servlet:11.0.12'
    // Jetty CDI集成模块,关键!
    implementation 'org.eclipse.jetty:jetty-cdi:11.0.12'

    // Weld Servlet环境支持
    implementation 'org.jboss.weld.servlet:weld-servlet-core:4.0.3.Final'

    // Jersey JAX-RS实现与Servlet容器集成
    implementation 'org.glassfish.jersey.containers:jersey-container-servlet-core:3.0.4'
    // Jersey CDI 2.0 SE 集成,关键!
    implementation 'org.glassfish.jersey.media:jersey-cdi2-se:3.0.4'
    // Jersey JSON处理支持
    implementation 'org.glassfish.jersey.media:jersey-media-json-jackson:3.0.4'

    // Jackson JSON处理库
    implementation 'com.fasterxml.jackson.core:jackson-core:2.12.7'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.7'

    // JUnit Jupiter for testing (可选)
    testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2'
}

application {
    mainClass = 'it.gym.StartApp' // 定义应用主类
}

tasks.named('test') {
    useJUnitPlatform()
}

注意事项:

  • jetty-cdi:这是Jetty与CDI容器(如Weld)进行集成的重要桥梁。
  • weld-servlet-core:提供了Weld在Servlet环境下的核心功能。
  • jersey-cdi2-se:Jersey框架与CDI 2.0 SE环境集成的模块,确保Jersey能够识别并利用CDI管理的Bean。
  • 版本兼容性:确保所有库的版本相互兼容。上述示例中使用了Jetty 11.0.12,Weld 4.0.3.Final和Jersey 3.0.4,这些版本被验证可以协同工作。

2. 核心应用启动类

接下来,我们需要编写主启动类来初始化Jetty服务器、配置Servlet上下文,并正确地集成Weld CDI。

package it.gym;

import org.eclipse.jetty.cdi.CdiDecoratingListener;
import org.eclipse.jetty.cdi.CdiServletContainerInitializer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
import org.jboss.weld.environment.servlet.EnhancedListener;

public class StartApp {

    public static void main(String[] args) {
        // 1. 初始化Weld SE容器
        // Weld weld = new Weld(); // 在此集成方式下,通常不需要手动初始化Weld SE容器
        // WeldContainer container = weld.initialize(); // 而是通过ServletContainerInitializer来完成

        final Server server = new Server(9000); // 监听端口9000
        final ServletContextHandler context = new ServletContextHandler(
                ServletContextHandler.SESSIONS);
        context.setContextPath("/"); // 设置应用根路径

        // 2. 关键的Weld CDI与Jetty集成配置
        // 这是Weld推荐的与Jetty集成的方式,取代了旧的addEventListener和setAttribute方法
        context.setInitParameter(
                CdiServletContainerInitializer.CDI_INTEGRATION_ATTRIBUTE,
                CdiDecoratingListener.MODE);
        context.addServletContainerInitializer(new CdiServletContainerInitializer());
        context.addServletContainerInitializer(new EnhancedListener());

        // 3. 配置Jersey ServletContainer
        final ServletHolder servletHolder = new ServletHolder(
                ServletContainer.class);
        servletHolder.setInitOrder(1); // 保证Servlet在其他组件之前初始化
        servletHolder.setInitParameter(
                "jersey.config.server.provider.packages",
                "it.gym.rest"); // 指定Jersey扫描REST资源类的包路径

        context.addServlet(servletHolder, "/rest/*"); // 将Jersey Servlet映射到/rest/*路径

        server.setHandler(context); // 将上下文处理器设置到服务器

        // 4. 启动服务器
        try {
            server.start();
            server.join(); // 阻塞主线程,直到服务器停止
        } catch (Exception e) {
            e.printStackTrace();
            // 确保在异常发生时关闭Weld容器,如果之前手动初始化了
            // if (container != null) {
            //     container.shutdown();
            // }
        } finally {
            // 如果Weld在SE模式下手动初始化,这里需要关闭
            // 如果是通过ServletContainerInitializer启动,则由容器管理生命周期
        }
    }
}

CDI 集成重点解释:

为了确保Weld CDI能够正确地发现并管理Bean,以及Jersey能够利用这些Bean进行依赖注入,关键在于ServletContextHandler的配置。

智川X-Agent
智川X-Agent

中科闻歌推出的一站式AI智能体开发平台

下载
  • context.setInitParameter(CdiServletContainerInitializer.CDI_INTEGRATION_ATTRIBUTE, CdiDecoratingListener.MODE);: 这个初始化参数告诉Jetty的CDI集成模块,应该使用CdiDecoratingListener模式来处理CDI事件。CdiDecoratingListener允许CDI容器监听并响应Servlet生命周期事件,从而正确地管理请求范围(@RequestScoped)等上下文。
  • context.addServletContainerInitializer(new CdiServletContainerInitializer());: CdiServletContainerInitializer是Jetty CDI模块提供的一个ServletContainerInitializer实现。它负责在Servlet容器启动时,初始化CDI环境,并将其与Jetty的生命周期事件关联起来。
  • context.addServletContainerInitializer(new EnhancedListener());: EnhancedListener是Weld Servlet环境提供的一个ServletContainerInitializer。它进一步增强了Weld在Servlet环境下的功能,确保了Weld BeanManager的可用性和CDI上下文的正确激活。

通过这三行配置,我们有效地将Weld CDI容器与Jetty的Servlet容器生命周期绑定,解决了CDI Bean无法被正确发现和注入的问题。

3. RESTful 资源与 CDI Bean

现在,我们可以定义我们的RESTful资源类和CDI Bean,并利用CDI进行依赖注入。

RESTful 资源类 (GymEndpoint.java):

package it.gym.rest;

import java.util.List;

import it.gym.dao.GymDAO;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;

@Path("/") // 定义根路径
@RequestScoped // 将此资源类声明为请求范围的CDI Bean
public class GymEndpoint {

    @Inject // 注入GymDAO实例
    private GymDAO gymDAO;

    @GET // 处理HTTP GET请求
    @Path("/test") // 映射到/rest/test路径
    public Response test() {
        List<String> entity = gymDAO.getDevices();
        return Response.status(Status.OK).entity(entity).build();
    }
}

CDI Bean (GymDAO.java):

package it.gym.dao;

import java.util.ArrayList;
import java.util.List;

import jakarta.enterprise.context.RequestScoped; // 声明为请求范围的CDI Bean

@RequestScoped
public class GymDAO {

    public GymDAO() {
        // CDI Bean通常有一个无参构造器
    }

    public List<String> getDevices() {
        // 模拟数据访问逻辑
        return new ArrayList<>();
    }
}

在GymEndpoint中,我们使用@Inject注解来声明对GymDAO的依赖。由于GymDAO被@RequestScoped注解标记,Weld CDI容器会在每次HTTP请求到达时,自动创建一个GymDAO实例并注入到GymEndpoint中。正确的CDI集成确保了这一过程的无缝执行。

4. 注意事项与总结

  • CDI Bean发现: 对于Weld而言,通常需要在项目的META-INF目录下放置一个空的beans.xml文件,以告知Weld扫描该归档文件中的CDI Bean。然而,在嵌入式环境中,尤其是在通过ServletContainerInitializer方式集成时,Weld可能会自动发现Bean,但作为最佳实践,beans.xml的存在可以确保CDI容器的激活。
  • 错误排查: 如果您遇到WELD-001408: Unsatisfied dependencies错误,这通常意味着CDI容器未能成功发现或实例化所需的Bean。请仔细检查以下几点:
    • 所有相关依赖是否正确引入且版本兼容。
    • CDI Bean(如GymDAO)是否正确使用了jakarta.enterprise.context包下的作用域注解(如@RequestScoped)。
    • Jetty的CDI集成配置(setInitParameter和addServletContainerInitializer)是否准确无误。
    • Jersey的jersey.config.server.provider.packages参数是否指向了包含REST资源类的正确包路径。
  • JAX-RS资源扫描: jersey.config.server.provider.packages参数至关重要,它告诉Jersey在哪里寻找带有@Path注解的类。确保路径正确无误,否则Jersey将无法发现您的RESTful服务。

通过遵循本文提供的依赖配置和Jetty启动类中的Weld CDI集成方法,您应该能够成功构建一个基于嵌入式Jetty、Jersey和Weld的独立RESTful应用程序,并有效利用CDI的依赖注入能力。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
PHP API接口开发与RESTful实践
PHP API接口开发与RESTful实践

本专题聚焦 PHP在API接口开发中的应用,系统讲解 RESTful 架构设计原则、路由处理、请求参数解析、JSON数据返回、身份验证(Token/JWT)、跨域处理以及接口调试与异常处理。通过实战案例(如用户管理系统、商品信息接口服务),帮助开发者掌握 PHP构建高效、可维护的RESTful API服务能力。

179

2025.11.26

servlet生命周期
servlet生命周期

Servlet生命周期是指Servlet从创建到销毁的整个过程。本专题为大家提供servlet生命周期的各类文章,大家可以免费体验。

393

2023.08.08

pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1947

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2119

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

1168

2024.11.28

http500解决方法
http500解决方法

http500解决方法有检查服务器日志、检查代码错误、检查服务器配置、检查文件和目录权限、检查资源不足、更新软件版本、重启服务器或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

495

2023.11.09

http请求415错误怎么解决
http请求415错误怎么解决

解决方法:1、检查请求头中的Content-Type;2、检查请求体中的数据格式;3、使用适当的编码格式;4、使用适当的请求方法;5、检查服务器端的支持情况。更多http请求415错误怎么解决的相关内容,可以阅读下面的文章。

450

2023.11.14

HTTP 503错误解决方法
HTTP 503错误解决方法

HTTP 503错误表示服务器暂时无法处理请求。想了解更多http错误代码的相关内容,可以阅读本专题下面的文章。

3538

2024.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.2万人学习

Java 教程
Java 教程

共578课时 | 80.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号