gpt4 book ai didi

rest - 如何在 Servlet 3.0 容器中将 JAX-RS 与 CDI 集成

转载 作者:行者123 更新时间:2023-12-04 03:21:30 28 4
gpt4 key购买 nike

我有一个使用 JSF 2.2 (Mojorra 2.1.3) 和 CDI 1.1 (Weld 2.0.3) 在 Servlet 3.0 容器 (Jetty 9.0.4) 上运行的 Web 应用程序。没有使用成熟的应用服务器。在这个应用程序中,我还有一个为 REST 请求提供服务的 JAX-RS 2.0 (Jersey 2.2) 资源类。我已经集成了 JAXB 绑定(bind)和 JSON 编码(Jackson 2.2)。我使用 Maven 3.0.5 进行构建管理。这些是我的项目设置的相关部分:

Maven pom.xml:

...
<dependencies>

<!-- Servlet 3.0 API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

<!-- Contexts and Dependency Injection for Java EE -->
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
<version>2.0.3.Final</version>
</dependency>

<!-- JavaServer Faces -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.2</version>
</dependency>

<!-- JAX-RS RESTful Web Services -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.2</version>
</dependency>

<!-- JSON Mapping Framework -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
...

部署描述符 web.xml:

...
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>

<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/jsf/*</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>my.package.config.RestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

<session-config>
<session-timeout>30</session-timeout>
</session-config>

<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>

<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>

<resource-env-ref>
<description>Object factory for the CDI Bean Manager</description>
<resource-env-ref-name>BeanManager</resource-env-ref-name>
<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
</resource-env-ref>
...

JAX-RS 根资源类:

@Path("/person")
public class PersonController
{
@Inject
private PersonService personService;

@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public List<Person> getAllPersons()
{
return personService.getAll();
}

@GET
@Path("/{index}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Person getPerson(@PathParam("index") int index)
{
return personService.get(index);
}

@POST
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public void savePerson(Person person)
{
personService.add(person);
}
}

JAX-RS 应用程序配置:

public class RestApplication extends ResourceConfig
{
public RestApplication()
{
// For JSON binding
register(new JacksonFeature());
register(new ApplicationBinder());
packages("my.package.controller");
}
}

JAX-RS 注入(inject)绑定(bind)配置:

public class ApplicationBinder extends AbstractBinder
{
@Override
protected void configure()
{
// Means something like: bind the field at an injection point of type PersonService to an instance of type PersonService
bind(PersonService.class).to(PersonService.class);
}
}

最后是 JSF 托管 bean:

@Named
@SessionScoped
public class PersonBean implements Serializable
{
private static final long serialVersionUID = 1L;

@Inject
private PersonService personService;

private Person newPerson = new Person();

public List<Person> getAll()
{
return personService.getAll();
}

public Person getNewPerson()
{
return newPerson;
}

public void setNewPerson(Person newPerson)
{
this.newPerson = newPerson;
}

public Gender[] getGenders()
{
return Gender.values();
}

public String saveNewPerson()
{
personService.add(newPerson);
newPerson = new Person();

return "index";
}
}

最后,我希望能够在 REST 资源类和 JSF bean 中使用相同的应用程序范围的服务实例,但是我不能让 CDI 和 JAX-RS 一起工作。

JSF/CDI 部分工作正常,但注入(inject) REST 资源类并没有真正起作用。我阅读了一些文章,其中展示了两种不同的方法来组合 CDI 和 JAX-RS:第一个是使用 @ManagedBean 注释 REST 资源类。为了使类由 CDI 容器实例化并由 JAX-RS 容器管理:

@ManagedBean
@Path("/person")
public class PersonController
{
@Inject
private PersonService personService;
...

第二种方法是给类一个 CDI 范围,例如 @RequestScoped为了让类被 CDI 容器实例化和管理。

@Path("/person")
@RequestScoped
public class PersonController
{
@Inject
private PersonService personService;
...

这些方法都不适合我。我总是以以下异常结束:

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=PersonService,parent=PersonController,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,5643079)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:208)
at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:231)
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:328)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:454)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:158)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2296)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:590)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:577)
at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:172)

但是当将注入(inject)绑定(bind)配置更改为:

bind(PersonServiceImpl.class).to(PersonService.class);

现在注入(inject)以某种方式起作用,但是对于每个 REST 请求,我都会得到一个 PersonServiceImpl 的新实例注入(inject),即使此服务是应用程序范围内的。对我来说,这是一个指标,即 JAX-RS 组件与 CDI 组件完全分离,并且与 CDI/JSF 组件一样位于完全不同的环境或容器中。

所以我真的很想知道如何让这两个概念在纯 servlet 3.0 容器中协同工作。

最佳答案

我解决了我的问题。

问题是,Jersey JAX-RS 实现使用 HK2 依赖注入(inject)框架,而这个框架根本不知道 CDI bean。并遵循 this post 中接受的答案的想法,我使 CDI bean 可用于 HK2 注入(inject)绑定(bind),并且我的应用程序范围 bean 的注入(inject)现在工作正常。

但我真的很想知道为什么将 Java EE 的两个组成部分放在一起如此麻烦。

更新:正如 G. Demecki 在评论中提到的,不再需要这个解决方案!但它在问这个问题时帮助了我。

关于rest - 如何在 Servlet 3.0 容器中将 JAX-RS 与 CDI 集成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18963627/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com