admin管理员组

文章数量:1287626

I am trying to understand JAX-RS, CDI integration in Wildfly, specifically how the bean lifecycle looks like. The following behaviour is not what I expected. Below is drilled down example.

@Dependent
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
public class UserResourceImpl {

   @PostConstruct
   public void init() {
    System.out.println("UserResourceImpl init ...");
   }

   @PreDestroy
   public void destroy() {
    System.out.println("UserResourceImpl destroy ...");
   }

   @GET
   public Response test() {
    return Response.ok("{ \"answer\": \"working...\"}").build();
   }
 }

Simple REST resource implementation with @Dependent scope. Why I am annotating this bean explicitly because my beans.xml is configured like that.

<?xml version="1.0" encoding="UTF-8"?>
<beans version="4.0"
   xmlns="; xmlns:xsi=";
   xsi:schemaLocation="
      
      .xsd"
   bean-discovery-mode="annotated">

</beans>

Bean discovery mode is annotated. This is on purpose, since I am studying bean lifecycle and wanted to keep things in my control.

So when this simple application is deployed in Wildfly 32 application server, what I notice is that @PostContruct is called for each HTTP request being received. Even after I already see the response on the client application i.e. HTTP request is completed, @PreDestroy never get called. Even when application is terminated, @PreDestroy does not get called. Why?

Looking at the documentation from RESTEasy /6.2/userguide/#_default_scopes

A CDI bean that does not explicitly define a scope is @Dependent scoped by default. This pseudo scope means that the bean adapts to the lifecycle of the bean it is injected into. Normal scopes (request, session, application) are more suitable for Jakarta RESTful Web Services components as they designate component’s lifecycle boundaries explicitly. Therefore, the resteasy-cdi module alters the default scoping in the following way:

If a Jakarta RESTful Web Services root resource does not define a scope explicitly, it is bound to the Request scope.

If a Jakarta RESTful Web Services Provider or jakarta.ws.rs.Application subclass does not > define a scope explicitly, it is bound to the Application scope.

So I expect this to behave like @RequestScoped bean, calling both @PostConstruct and @PreDestroy for each completed HTTP request.

Could someone explain this to me? Is this a Bug?

I am trying to understand JAX-RS, CDI integration in Wildfly, specifically how the bean lifecycle looks like. The following behaviour is not what I expected. Below is drilled down example.

@Dependent
@Path("/users")
@Produces(MediaType.APPLICATION_JSON)
public class UserResourceImpl {

   @PostConstruct
   public void init() {
    System.out.println("UserResourceImpl init ...");
   }

   @PreDestroy
   public void destroy() {
    System.out.println("UserResourceImpl destroy ...");
   }

   @GET
   public Response test() {
    return Response.ok("{ \"answer\": \"working...\"}").build();
   }
 }

Simple REST resource implementation with @Dependent scope. Why I am annotating this bean explicitly because my beans.xml is configured like that.

<?xml version="1.0" encoding="UTF-8"?>
<beans version="4.0"
   xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3./2001/XMLSchema-instance"
   xsi:schemaLocation="
      https://jakarta.ee/xml/ns/jakartaee
      https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
   bean-discovery-mode="annotated">

</beans>

Bean discovery mode is annotated. This is on purpose, since I am studying bean lifecycle and wanted to keep things in my control.

So when this simple application is deployed in Wildfly 32 application server, what I notice is that @PostContruct is called for each HTTP request being received. Even after I already see the response on the client application i.e. HTTP request is completed, @PreDestroy never get called. Even when application is terminated, @PreDestroy does not get called. Why?

Looking at the documentation from RESTEasy https://docs.resteasy.dev/6.2/userguide/#_default_scopes

A CDI bean that does not explicitly define a scope is @Dependent scoped by default. This pseudo scope means that the bean adapts to the lifecycle of the bean it is injected into. Normal scopes (request, session, application) are more suitable for Jakarta RESTful Web Services components as they designate component’s lifecycle boundaries explicitly. Therefore, the resteasy-cdi module alters the default scoping in the following way:

If a Jakarta RESTful Web Services root resource does not define a scope explicitly, it is bound to the Request scope.

If a Jakarta RESTful Web Services Provider or jakarta.ws.rs.Application subclass does not > define a scope explicitly, it is bound to the Application scope.

So I expect this to behave like @RequestScoped bean, calling both @PostConstruct and @PreDestroy for each completed HTTP request.

Could someone explain this to me? Is this a Bug?

Share Improve this question edited Feb 26 at 7:44 office.aizaz asked Feb 23 at 14:18 office.aizazoffice.aizaz 3031 silver badge13 bronze badges 8
  • 1 Take it with a pinch of salt but this might be a bug in how resteasy handles the beans (i.e. that they are not destroying them) - @Dependent beans are a bit special and if you retrieve them outside of any other context, you also need to destroy them properly. That being said, why @Dependent? I'd say @RequestScoped is a much better fit for this? – Siliarus Commented Feb 24 at 8:58
  • Also as a side note - with WFLY 32, you are actually using CDI 4.0 (whereas your question states 2.0). There is no breaking change with regard to your question, just as an FYI. – Siliarus Commented Feb 24 at 9:01
  • @Siliarus Absolutely @RequestScoped makes sense. Most of research I did on internet is also suggesting the same. I wanted to understand the relationship with HTTP requests and CDI beans. I understand how @Dependent scoped beans utlimately adopt the scope of the beans where are being injected into. JAXRS resources for me are bit of mystery. They are not really CDI, so I wondered what happens if the resources are annotated. I guess, CDI simply cares for the annotated beans (in my case because of beans.xml) and is not aware of that same bean is also a JAXRS resource. – office.aizaz Commented Feb 24 at 13:45
  • Where do you think an instance of UserResourceImpl should be injected to define it as a CDI bean? The fact that the classes are annotated as CDI only means that CDI can manage it. – mr mcwolf Commented Feb 24 at 16:20
  • @mrmcwolf I understand what you mean. The question would be why would I be annotating UserResourceImpl at all with CDI scopes. I would do that, if I want to use CDI inside a JAX-RS resource. By annotating this resource, I already make it a CDI bean managed by CDI container. Now the question remains, when an HTTP requests is received by application server, JAX-RS handles it and triggers my resource. When using e.g. @RequestScoped , who/how tells CDI to create this CDI bean and destroy it when request is completed? I guess JAX-RS (somehow). So in a way, this class is injected in JAXRS? :S – office.aizaz Commented Feb 24 at 17:05
 |  Show 3 more comments

1 Answer 1

Reset to default 1

Minor nit, if you're using WildFly 32 you're using Jakarta REST 3.1.

By default RESTEasy uses @RequestScoped for endpoints and @ApplicationScoped for jakarta.ws.rs.core.Application's and providers.

Since you defined @Dependent, you're effectively saying "give me a new bean each time" as you're not injecting that Jakarta REST resource into another scoped bean. As to why the bean is not being destroyed, I'm not sure yet. The JavaDoc is a bit odd IMO.

When the container destroys an instance of a bean or of any Java EE component class supporting injection, the container destroys all its dependent objects, after the @PreDestroy callback completes and after the servlet destroy() method is called.

While RESTEasy itself does support Servlet, there is no requirement in the Jakarta REST specification that a Servlet be used. I'll have to look into why the beans are not getting destroyed.

All this said, I do think @Dependent is the wrong scope for a Jakarta REST endpoint and you're better to, at a minimum, use @RequestScoped endpoints.

本文标签: jax rsCDI 40 Integration with Jakarta REST 31 in WildFly serverStack Overflow