ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
- **REST 接口**里看到 `@Produces`,想“**返回什么格式给客户端**”。 - **依赖注入**里看到 `@Produces`,想“**工厂方法产出 Bean 实例**”。 ``` @Produces(MediaType.APPLICATION_JSON) ``` >[info]详细解释 在 Java 里,“@Produces”这个名字一共出现在两套常用规范里,它们的作用完全不同。先给出结论,再分条展开: 1. **JAX-RS(Java-RS,REST 接口)里的 @Produces** 放在“资源方法/类”上,声明“我能**产生(produce)**哪种 MIME 类型的响应体”。 典型实现:Jersey、RESTEasy、CXF、Spring MVC 的 `@RequestMapping` 也借鉴了同样思路。 2. **CDI(JSR-365,依赖注入)里的 @Produces** 放在“**工厂方法**或**字段**”上,声明“这个方法是** Bean 的制造工厂**,由它‘产出’对象实例供注入”。 典型实现:Weld、OpenWebBeans。 -------------------------------- 一、JAX-RS 中的 @Produces(javax.ws.rs.Produces) 1. 作用 - 告诉容器:当客户端发起请求时,本方法/类返回的实体(Entity)将被序列化成哪种媒体类型。 - 与 `@Consumes`(我能消费什么)对应,是 HTTP 内容协商(Content-Negotiation)的核心注解之一。 2. 使用位置 - 资源类级别:对该类所有方法生效。 - 资源方法级别:仅对该方法生效,会覆盖类级别声明。 3. 常见写法 ```java @Path("/books") @Produces(MediaType.APPLICATION_JSON) // 类级默认 public class BookResource { @GET @Path("{id}") @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Book getBook(@PathParam("id") Long id) { … } } ``` - 支持数组,越靠前的类型优先级越高。 - 常量类 `MediaType` 里预定义了常用值,也可以直接写字符串 `"text/plain;charset=utf-8"` 等。 4. 运行流程 1. 容器根据请求头 `Accept: application/xml, text/plain;q=0.9` 与 `@Produces` 列表做匹配。 2. 找到最匹配的 `MessageBodyWriter`,将 Java 对象序列化为对应格式。 3. 把 `Content-Type` 响应头设置成最终选中的类型。 5. 与 @Consumes 的区别 - `@Consumes` 过滤“我能处理什么请求格式”。 - `@Produces` 过滤“我能给出什么响应格式”。 二者组合可实现同一 URL 根据请求头区分 JSON/XML 版本。 -------------------------------- 二、CDI 中的 @Produces(javax.enterprise.inject.Produces) 1. 作用 - 把“**普通方法/字段**”标记为“** Bean 供应源**”,解决“第三方类、运行时才确定的实例、需要复杂初始化逻辑”等无法直接用 `@ApplicationScoped`、`@Inject` 的场景。 2. 使用位置 - 方法:称为“producer method”。 - 字段:称为“producer field”。 二者通常配合作用域注解(`@ApplicationScoped`、`@RequestScoped`…)决定生命周期。 3. 典型例子 ```java @ApplicationScoped public class ConfigFactory { @Produces // 关键点 @ApplicationScoped @Named("globalConfig") // 给 EL 或 @Named 注入时用的名字 public Properties produceConfig() { Properties p = new Properties(); p.load(...); return p; } } ``` 以后任何地方都可以: ```java @Inject @Named("globalConfig") private Properties cfg; ``` 4. 与 @Disposes 配对 如果 producer 返回的对象需要显式清理(如数据库连接),可以在另一个方法参数上加 `@Disposes`,CDI 会在上下文销毁时自动回调。 5. 优势 - 不需要修改第三方源码就能让它成为 CDI Bean。 - 运行期才能决定实现类(策略模式)时,把选择逻辑写在 producer 里即可。 -------------------------------- 三、一句话区分记忆 - **REST 接口**里看到 `@Produces`,想“**返回什么格式给客户端**”。 - **依赖注入**里看到 `@Produces`,想“**工厂方法产出 Bean 实例**”。 两套注解同名但用途迥异,阅读代码时先确认所在规范即可快速判断。