CDI injection in a JSP

2019-06-23 04:15发布

问题:

Within a JSP it is possible to use CDI managed beans using EL expressions such as ${myBean.myAttribute}. No problem here.

I would like to use "regular injection" (i.e. without using EL expressions) with @Inject in JSP files, for example : <%! @Inject MyBean myBean; %> then later <%= myBean.getMyAttribute() %>. Even if that example can be achieved using EL expressions, some other use cases cannot.

This does not seem to be completely supported by app servers:
- JBoss 6.0.0, JBoss 6.1.0, Resin 4.0.22: OK, it works just fine.
- JBoss 7.0.1, GlassFish 3.x (several versions were tested): FAILS, myBean remains null.

It should work fine in a JSP since :
(1) it works fine in servlets according to the various concerned specifications and
(2) JSP get translated to servlet during runtime.

Do you guys know if what I'm trying to do is supported or not? Any inside/implementation information maybe?

回答1:

Interesting question, if you hadn't been testing it, I would have bet some money on the fact the it does not work ;-)

CDI builds on managed beans (JSR 316). The corresponding definition is pretty relaxed (on purpose):

From the spec:

A Managed Bean can be declared by annotating its class with the javax.annotation.ManagedBean annotation. A Managed Bean must not be: a final class, an abstract class, a non-static inner class. A Managed Bean may not be serializable, unlike a regular JavaBean component.

In the basic component model, Managed Beans must provide a no-argument constructor, but a specification that builds on Managed Beans, such as CDI (JSR-299), can relax that requirement and allow Managed Beans to provide constructors with more complex signatures,

What's probably happening is that the container scans the classpath and happens to find the compiled JSP servlets. It's a while since I last saw one, but I remember that the code is generated and everything (including scriptlets) lands in doGet() or doPost()...!? So, even though they formally do not disqualify in terms of the definition, I doubt that a JSP scriplet is anything that you want to consider a managed bean. It feels terribly wrong, honestly ;-)

I'm following the CDI / Weld / Seam mailing lists since quite a while, and don't recall that JSP has ever been mentioned. Same with googling this connection.

As a consequence you should not rely on CDI working with scriptlets. IMHO this behaviour has more of a side effect than of something intenional and can be dropped in future releases without notice (or even without being noticed :-)

So, +1 for the proposal of JB Nizet: Use servlets with CDI, but not JSPs.

UPDATE: I tried to help, not to create confusion ;-) My point is: IMHO it feels really really wrong to use CDI in JSPs, but I did not find anything in the relevant specs that proves this. All I can say is that JSPs are never mentioned anywhere - which kind of supports my gut feeling (and fits the observation that some implementations do consider it, others don't).



回答2:

I don't think there is a portable @Inject available out-of-box for JSP, but it should be possible to implement it (at the container level) the same way it works with servlets.

And while I agree that's it not the best way to utilize CDI, technically I don't see any reason against it. For example, AFAIK @Inject in servlets transparently uses ThreadLocal proxies, why not use this feature in JSP's?



回答3:

Try this :-

<%!
    @Inject
    private UserService userService;
%>

It's working for me :)

Note: Use bracket <%! %> instead of <% %>.