Nowhere in the CDI spec it is said that bean instances retrieved from {{Instance.get()}} and from iterating with {{Instance.iterator()}} should be treated differently regarding their destruction. In other words, it's normal that {{Instance.get()}} and {{Instance.iterator().next()}} behave the same. So your trick is exploiting a bug in Weld 1.1
Weld 2.3 is behaving correctly according to CDI 1.2 spec. You're using {{Instance}} to request instances for dependent beans. [Section 6.4.2 of the spec|http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#dependent_destruction] reads:
{quote}Dependent objects of a contextual instance are destroyed when {{Contextual.destroy()}} calls {{CreationalContext.release()}}, as defined in The {{CreationalContext}} interface.
Additionally, the container must ensure that:
* all dependent objects of a non-contextual instance of a bean or other Java EE component class are destroyed when the instance is destroyed by the container,{quote}
We are in this case. The CDI container doesn't guarantee that all instances will be destroyed with the destruction of injecting servlet. So don't expect it to happen during your servlet life. You have to use {{Instance.destroy()}} method to explicitly cleanup your dependent instances.
Now, why don't you experience memory leak when {{CDIBean2}} is injected directly and not thru {{Instance<CDIBean2>}}?
Probably because Weld use an optimisation allowed by the spec (end of section 6.4.2):
bq. Finally, the container is permitted to destroy any {{@Dependent}} scoped contextual instance at any time if the instance is no longer referenced by the application (excluding weak, soft and phantom references).
But as you see it's not guarantee: Weld is doing you a favour here.
So to comply to CDI code spec , your example should be modified like this:
{code:java} @WebServlet("/Servlet") public class Servlet extends HttpServlet { private static final long serialVersionUID = 1L;
@Inject private Instance<CDIInterface> cdi; /** * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response) */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { CDIInterface myInterface = cdi.get(); response.getWriter().write("Here " + Servlet.class.getName() + " - " + myInterface.sayHello()); cdi.destroy(myInterface); }
}
public interface CDIInterface {
public abstract String sayHello(); }
@Default public class CDIBean implements CDIInterface{
@Inject private Instance<CDIBean2> bean2; public String sayHello() { CDIBean2 myBean2 = bean2.get(); return "Here " + CDIBean.class.getName() + " - " + myBean2.get().testHello(); bean2.destroy(myBean2); }
}
public class CDIBean2 {
public String testHello() { return "Here " + CDIBean2.class.getName(); } } {code}
|
|