Injecting EJB3.0 Beans into JSF2.0 Backing Beans... Impossible?
I'm working on a JSF project on Weblogic 11g, and our initial design is calling for JSF Backing Beans to invoke EJB3.0 beans to perform business logic开发者_运维百科 and data access calls. The @EJB annotation doesn't seem to work in my project when I try to inject the EJB reference to the backing bean. Whenever I hit the class that I am testing, the constructor for my EJB is never called and I end up with a NPE. Is it possible to inject an EJB3.0 bean into a JSF backing bean? Is there another way I should be invoking an EJB through the JSF Backing bean? What is the best practice?
I googled somewhat and this indeed seems to be a known issue with Weblogic. Lot of similar topics are kept unanswered.
I found this blog which confirms that @EJB
in Weblogic only works for resources definied by web.xml
, not for JSF. The blog describes also in detail a workaround using ServletContextListener
which is IMO not much better than using JNDI.
I also found this OTN topic which confirms that @EJB
in Weblogic started to work when EJB modules are not included in subdirectories (see the answer posted at the bottom, Feb 15, 2011 5:44 PM).
It turns out that it is a Weblogic specific issue when deploying anything using JSF and EJB. I found this post on the Oracle forums that explains how to get the @EJB injection working in JSF Managed Beans using Weblogic 11g:
EJB3.0 Injection into JSF Managed beans
UPDATE:
After spinning my wheels for too long, I have to give up trying to inject an EJB into a JSF ManagedBean on Weblogic 11g. Seems to work fine in Tomcat. Maybe the EJB3 and JSF implementation will be better in 12G...
To make it work you need to follow two steps:
- Deploy jsf-2.0.war as LIBRARY, you can find it /ORACLE_HOME/wlserver_10.3/common/deployable-libraries
In your web project, add the reference to the jsf-2.0.war library in WEB-INF/weblogic.xml
<?xml version="1.0" encoding="UTF-8"?> <wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.1/weblogic-web-app.xsd"> <wls:weblogic-version>10.3.3</wls:weblogic-version> <wls:context-root>your_context_app</wls:context-root> <wls:library-ref> <wls:library-name>jsf</wls:library-name> <wls:specification-version>2.0</wls:specification-version> <wls:implementation-version>1.0.0.0_2-0-2</wls:implementation-version> <wls:exact-match>true</wls:exact-match> </wls:library-ref> </wls:weblogic-web-app>
I have successfully tested this in weblogic 10.3.3 and 10.3.5. If somehow this does not work, try to deploy the application as part of EAR file.
So here is the beat! There is a simple way to fix this.
Open up jsf-2.0.war under ...wlserver_10.3\common\deployable-libraries
Navigate to WEB-INF/lib and save wls.jsf.di.jar JAR somewhere
Place wls.jsf.di.jar JAR under lib folder of your WAR application.
Deploy
all should work now just by adding @EJB to property in your @ManagedBean.
There is an alternative for the @EJB annotation in order to get your local EJB bean accessible in your JSF ManagedBean web application. Considering that you have your EJB classes and your WAR packaged in the same EAR file, do the following:
configure your ejb-jar.xml to tell the weblogic expose the EJB beans to the external components;
<enterprise-beans> <session> <ejb-name>MyEJBBean</ejb-name> <business-local>com.app.MyEJBBeanLocalInterface</business-local> <ejb-class>com.app.MyEJBBeanLocalImpl</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> <ejb-local-ref> <ejb-ref-name>ejb/MyEJBBeanLocal</ejb-ref-name> <local>com.app.MyEJBBeanLocalInterface</local> </ejb-local-ref> </session> <enterprise-beans>
Insert in the web.xml of your web application a reference to the EJB throught the ejb-link name. The ejb-ref-name is name visible for the JSF managed beans.
<ejb-local-ref> <ejb-ref-name>ejb/MyEJBBeanLocal</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <local>com.app.MyEJBBeanLocalInterface</local> <ejb-link>MyEJBBean</ejb-link> </ejb-local-ref>
In your JSF Managed Bean call the EJB Bean through JNDI lookup as the following:
try { Context context = new InitialContext(); MyEJBBeanLocalInterface myEJBBean = context.lookup("java:comp/env/ejb/MyEJBBeanLocal"); } catch (NamingException e) { e.printStackTrace(); }
In my case I was using the Weblogic 10.3.6 (11g), JSF 2.0 and EJB 3.0 with JPA (Eclipselink)
精彩评论