JSF is very popular technology in Java world, however, cooperation with Spring is still painfull and requires 'nasty' hacks. I have currently the problem with one of this 'hacks'.
Spring services are injected using the SpringBeanFacesELResolver
. It is configured in faces-config.xml
:
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
The injection of Spring services is very ugly, but it is working:
@ManagedProperty(value="#{customerService}")
CustomerService customerService;
But there are issues. JSF requires from me that the managed bean should be serializable. That means, that the Spring service must also be serializable, or the field should be transient. When the field is transient, the injection is not working (I have null in that field). And making Spring services serializable is in my opinion not a good idea and a potential performance issues - what should happen with Hibernate context, data sources, which all are injected into Spring service?
So, what is the correct and less painfull way of using Spring services withing JSF managed beans?
I experienced a lot of issues with org.springframework.web.jsf.el.SpringBeanFacesELResolver, too. Mostly related to unmatching object scopes (Spring has no equivalent to JSF's view scope and conversation scope). Some people also complain about serialization problems.
I successfully applied the solution proposed in this article: http://www.beyondjava.net/blog/integrate-jsf-2-spring-3-nicely/.
In my case, serialization, was not a problem and I was only concerned with bean scopes. I wished JSF to fully manage the backing beans lifecycle without interference with Spring beans lifecycle.
I made JSF managed beans to load the Spring context and autowire themselves to access Spring-managed beans from the JSF context.
I developed the following JSF bean superclass:
public abstract class AutowireableManagedBean {
protected AutowireCapableBeanFactory ctx;
@PostConstruct
protected void init() {
logger.debug("init");
ctx = WebApplicationContextUtils
.getWebApplicationContext(
(ServletContext) FacesContext.getCurrentInstance()
.getExternalContext().getContext())
.getAutowireCapableBeanFactory();
// The following line does the magic
ctx.autowireBean(this);
}
...
}
Then, my concrete JSF backing beans looked like this (I was able to use view scope without problems):
@ManagedBean
@ViewScoped
public class MyBackingBean extends AutowireableManagedBean {
@Autowired
private MyDao myDao;