将 JAX-RS 2.0 与 EJB 和 CDI 集成
Liberty 中的 JAX-RS 2.0 与 Enterprise JavaBeans (EJB) 及上下文和依赖关系注入 (CDI) 集成。
为使 JAX-RS 2.0 使用企业 bean,您需要使用 @Path 注释 bean 的类并将其转换为根资源类。
通过与 EJB 集成,您可注释 EJB bean 以将它们展示为 REST 端点。还可使用 EJB 的 JTA 和安全功能。Liberty 中的 JAX-RS 2.0 支持使用无状态 bean 和单独会话 bean 作为根资源类、提供者和应用程序子类。通过与 CDI 集成,您可注释 CDI bean 或受管 bean 作为 REST 端点并对 Web Service 使用 CDI 注入。Liberty 中的 JAX-RS 2.0 支持 CDI 样式的 bean 作为根资源类、提供者和应用程序子类。提供者和应用程序子类必须是单体或使用应用程序范围。CDI 规范简化了集成不同类型的 Java™ EE 组件的过程。它提供可将组件(例如 EJB 组件或受管 bean)注入其他组件(例如 JSP 或其他 EJB)的一种常用机制。
对于 EJB,可将注释与无状态会话 bean 和单体 POJO bean 配合使用。
- 对于无状态会话 bean,请按以下示例中所示使用 @Stateless 注释:
@Stateless @Path("stateless-bean") public class StatelessResource {...}
- 对于单体 bean,请按以下示例中所示使用 @Singleton 注释:
@Singleton @Path("singleton-bean") public class SingletonResource {...}
对于 CDI,可将 @ApplicationScoped 和 @Inject 注释与应用程序范围的 bean 配合使用。
提示: 如果 CDI 功能部件被禁用,那么 JAX-RS 不会报告错误,但会通过使用 POJO 获取实例。
@ApplicationScoped
@Path("/ApplicationScopedResource")
public class ApplicationScopedResource {
private @Inject
SimpleBean injected;
...
}
对 JAX-RS 2.0 与 EJB 和 CDI 的限制
请参阅以下各项以了解 Liberty 中的 JAX-RS 2.0 的限制:
- 如果使用 EJB 作为 JAX-RS 资源、提供者或应用程序,那么不能对 EJB bean 的构造函数使用 @Context 注入。原因在于根据 EJB 和 JAX-RS 规范,只能对 JAX-RS 使用带有缺省构造函数的 EJB。
- 如果在 Java 类中使用 EJB 或 CDI 注释,但未在 server.xml 文件中配置 EJB(例如,ejbLite-3.2)或 CDI(例如,cdi-1.0)的 Liberty 功能部件(这意味着 Liberty 运行时中没有 EJB 或 CDI 支持),那么 JAX-RS 2.0 引擎使用 Java 类作为 POJO 类。
- 对于应用程序类,如果它未实现任何接口或者它具有 @Localbean 注释,那么它被视为 EJB;如果它实现本地接口或 POJO 接口,那么它不会被视为 EJB。
- 对于提供者:
- 如果类仅实现 POJO 提供者接口而没有 @Local 注释,那么它被视为有效 EJB 提供者。
- 如果类有 @LocalBean 注释并实现 POJO 提供者接口,那么它被视为有效 EJB 提供者。
- 如果类有带 @Local 注释的本地接口,那么本地接口是提供者接口。如果此类实现提供者接口,那么它是有效 EJB 提供者。
- 如果类有带 @Local 注释的本地接口,并且该本地接口不是提供者接口,那么它不是有效提供者。
原因是在此情况下,EJB 容器只能为本地接口而不是 POJO 提供者接口生成 EJB 存根。
- 如果类只有引用提供者接口的 @Local 注释,而未实现此提供者接口,那么它不是有效提供者;根据 JAX-RS 2.0 规范:提供者是一个类,该类实现此规范中引入的一个或多个 JAX-RS 接口,并可使用 @Provider 进行注释以执行自动发现。
- 对于资源:
- 如果基于 EJB 的资源未实现任何接口,那么此类中声明的所有方法可作为 JAX-RS 资源提供。
- 如果基于 EJB 的资源实现一个接口(本地或 POJO),那么此接口中声明的所有方法以 JAX-RS 资源形式提供。
- 如果基于 EJB 的资源实现多个接口,那么:
- 所有接口是不带 @Local 注释的 POJO 接口时,接口中声明的所有方法以 JAX-RS 资源形式提供。
- 所有接口是带 @Local 注释的本地接口时,接口中声明的所有方法以 JAX-RS 资源形式提供。
- 某些接口是带 @Local 注释的本地接口而其他接口不是本地接口时,只有本地接口中声明的方法才以 JAX-RS 资源形式提供。原因在于,EJB 容器只能为本场景中的本地接口生成 EJB 存根。
- 如果基于 EJB 的资源具有 @LocalBean 注释,那么类中声明的所有方法以 JAX-RS 资源形式提供。
- 如果基于 EJB 的资源实现接口,那么必须在该接口中声明 JAX-RS 资源方法。如果该接口是不能修改的提供者,那么您必须为资源类创建新接口以添加资源方法。否则,它不会被视为 EJB 资源。
- 对于提供者:
- 如果带 @Path 注释的资源类实现 JAX-RS 提供者接口或者它使用 @Provider 注释进行声明,那么此类同时充当资源和提供者。在此情况下,JAX-RS 2.0 引擎仅使用此类的一个实例(由资源和提供者共享),此实例的生命周期为单体,这是缺省情况。
- 如果某个类已在应用程序类的 getClasses 和 getSingletons 方法中进行了注册,那么缺省情况下,JAX-RS 2.0 引擎使用 getSingletons 方法中的实例并忽略 getClasses 方法中的注册。
- 如果 RESTful 资源也是 CDI 管理的 bean 并且其范围为 javax.enterprise.context.Dependent,那么会因为 CDI 限制而不能调用 PreDestroy 方法。
JAX-RS 2.0 bean 和 EJB bean 生命周期
JAX-RS bean 与 EJB bean 具有不同生命周期。如果该 JAX-RS 和 EJB 两者的 bean 生命周期冲突,那么生命周期由
Liberty 中的 EJB 容器管理。所以,JAX-RS 生命周期不起作用时,系统会应用 EJB 实例。有关更多信息,请参阅下表:
应用程序 | JAX-RS 2.0 | EJB | 结果 |
---|---|---|---|
资源 | perRequest | 无状态 | 无状态 |
perRequest | 单体 | 单体 | |
单体 | 无状态 | 无状态 | |
单体 | 单体 | 单体 | |
提供者 | 单体 | 无状态 | 无状态 |
单体 | 单体 | 单体 |
JAX-RS 2.0 范围和 CDI 范围生命周期
Bean 的范围确定其实例的生命周期。JAX-RS 和 CDI 两者的范围稍有不同。如果 JAX-RS 和 CDI 的范围生命周期冲突,请参阅下表以获取结果:
应用程序 | JAX-RS 2.0 范围 | CDI 范围注释 | 结果 |
---|---|---|---|
资源 | perRequest | @ApplicationScoped | 单体 |
perRequest | @RequestScoped | perRequest | |
perRequest | @Dependent | perRequest | |
perRequest | @SessionScoped | Session | |
perRequest | perRequest | ||
单体 | @ApplicationScoped | 单体 | |
单体 | @RequestScoped | perRequest | |
单体 | @Dependent | 单体 | |
单体 | @SessionScoped | 会话 | |
单体 | 单体 | ||
提供者 | 单体 | @ApplicationScoped | 单体 |
单体 | @RequestScoped | 单体 | |
单体 | @Dependent | 单体 | |
单体 | @SessionScoped | 单体 | |
单体 | 单体 |
JAX-RS 2.0 范围和 CDI 范围生命周期冲突消息
如果 JAX-RS 2.0 与 CDI 两者的范围生命周期冲突,那么会显示以下警告消息。它们只是警告消息,不需要执行任何操作。
如果 JAXRS-2.0 资源范围与 CDI 范围不匹配并且 CDI 中存在该资源实例(导致 Liberty 从 CDI 获取该资源实例),那么会显示此消息。如果实例来自 JAX-RS,那么它未包含 CDI 注入。CWWKW1001W: JAXRS-2.0 资源 {0} 的范围 {1} 与 CDI 范围 {2} 不匹配。Liberty 从 {3} 获取资源实例。
显示此消息的原因是该提供者实例仅为“单体”。如果该提供者的 CDI 范围是“依赖”或 ApplicationScoped,那么 Liberty 从 CDI 获取该提供者实例。如果实例来自 JAX-RS,那么它未包含 CDI 注入。CWWKW1002W: JAXRS-2.0 提供者 {0} 的 CDI 范围为 {1}。Liberty 从 {2} 获取该提供者实例。