Spring bean is not injected into JSF managed bean (which is an abstract superclass)
I have an abstract super class bean called FooBean and all of my other beans extend this class. I have wired up my dao in applicationContext files and I want to inject it into this superclass bean so that every time I am inside of a bean, I have access to the dao. The problem is, I get a NullPointerException whenever I try to access the dao in a subclass. The following files show only the relevant config details for spring setup:
web.xml:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<context-param>
<description>Spring configuration files location.</description>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/applicationContext-*.xml</param-value>
</context-param>
faces-config.xml:
<application>
<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
...
</application>
FooBean.java:
public abstract class FooBean implements Serializable {
protected transient FooService dao;
public void setFooService(FooService dao){
this.dao = dao;
}
}
applicationContext-service.xml:
<bean id="serviceTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="*"/>
<!--
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
-->
</props>
</property>
</bean>
<!-- Definition of service targets -->
<bean id="fooServiceTarget" class="com.foo.service.FooService">
<property name="fooDAO" ref="fooDAO"/>
<property name="adminDAO" ref="adminDAO"/>
<property name="channelsDAO" ref="channelsDAO"/>
</bean>
<bean id="fooService" parent="serviceTemplate">
<property name="target" ref="fooServiceTarget"/>
</bean>
applicationContext-hibernate.xml:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/FooDataSource"/>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<!--value>com/Foo/model/General.hbm.xml</value-->
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.sho开发者_C百科w_sql">true</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
<prop key="hibernate.search.default.indexBase">/usr/lucene/indexes</prop>
<!--prop key="hibernate.cache.provider_class">org.hibernate.cache.SwarmCacheProvider</prop-->
</props>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- Spring Data Access Exception Translator Defintion -->
<bean id="jdbcExceptionTranslator" class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator"/>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
<property name="jdbcExceptionTranslator" ref="jdbcExceptionTranslator"/>
</bean>
<!-- Add DAO's here and create separate application context for service -->
<bean id="FooDAO" class="com.foo.service.dao.impl.FooDAOHibernate">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
<bean id="adminDAO" class="com.foo.service.dao.impl.AdminDAOHibernate">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
<bean id="channelsDAO" class="com.foo.service.dao.impl.ChannelsDAOHibernate">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
Things I already tried with no success:
- Tried using @ManagedProperty(value="#{FooService}") on the FooBean class field.
Tried defining a bean in faces-config.xml to inject the spring bean:
com.foo.beans.FooBean none fooService #{fooService}
Defined the subclass bean that had the null pointer as a spring bean and injecting the property via the spring beans xml file.
Ironically, I am able to place the following code in the constructor of the FooBean abstract class and the dao is injected (but I don't want to use this code, I want spring to inject it):
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getRequest().getServletContext());
dao = (FooService)ctx.getBean("fooService");
(I would have written this as a comment but I don't have enough reputation for it)
If you used @ManagedProperty, then you should also have declared it a @ManagedBean.
Also, I don't see FooBean in any of the applicationContext.xml files, so I don't see how Spring would "know" about it.
Believe this has to do with the way jsf beans are used. When a new bean is requested, the dao will not be injected due to Spring Injects being instantiated at deploy time. The reason it works in the constructor is the bean is created for the request, then you're getting the app context and grabbing the dao Singleton.
精彩评论