Como integrar o JSF 2.0 com o Spring?

5 respostas
bland

Olá a todos!

Estou tendo alguns problemas para fazer essa integração. Eu tenho um ManagedBean e dentro dele eu tenho um serviço, que deveria ser populado pelo Spring. Só que sempre que chega no meu ManagedBean, o serviço está nulo. Assim como o EntityManager do serviço também. Vou postar alguns fontes.

O meu MangedBean :

@RequestScoped  //javax.faces.bean.RequestScoped
@ManagedBean( name = "productBean" )  //javax.faces.bean.ManagedBean
public class ProductManagedBean {

	@Autowired  //org.springframework.beans.factory.annotation.Autowired
	private ProductService productService;  // não está fazendo a injeção
	
	private Product product;
        
        // operações
}

Eu não tenho declarado esse serviço no applicationContext, mas tem essa linha lá: <context:component-scan base-package=“com.monteirosti” />

O applicationContext.xml :

&lt;beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:ws="http://jax-ws.dev.java.net/spring/core" xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://jax-ws.dev.java.net/spring/core
	       http://jax-ws.dev.java.net/spring/core.xsd
    	   http://jax-ws.dev.java.net/spring/servlet
		   http://jax-ws.dev.java.net/spring/servlet.xsd
           "&gt;

	&lt;context:property-placeholder location="classpath:/jdbc.properties" /&gt;

	&lt;!-- 
	&lt;aop:aspectj-autoproxy /&gt;
	 --&gt;

	&lt;!-- Indica ao spring que os beans estao representados por anotacoes --&gt;
	&lt;context:annotation-config /&gt;

	&lt;!-- Configuracao do DataSource	--&gt;
	&lt;bean id="pgDataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
		p:url="${url}"
		p:driverClassName="${driverClassName}" 
		p:username="${username}"
		p:password="${password}" /&gt;

	&lt;!--
		Gerencia as PersistenceUnits do JPA. Neste local deve ser indicado
		onde estao os arquivos que configuram as PersistenceUnits
	--&gt;
	&lt;bean id="persistenceUnitManager"
		class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"&gt;
		&lt;property name="defaultDataSource" ref="pgDataSource" /&gt;
	&lt;/bean&gt;

	&lt;!-- Gerenciador da criacao e manutencao dos EntityManager --&gt;
	&lt;bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"&gt;
		&lt;property name="persistenceUnitManager" ref="persistenceUnitManager" /&gt;
		&lt;property name="persistenceUnitName" value="devlp"/&gt;
		&lt;property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" /&gt;
		&lt;property name="jpaVendorAdapter"&gt;
            &lt;bean
                class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"&gt;
                &lt;property name="database" value="POSTGRESQL" /&gt;
                &lt;property name="showSql" value="true" /&gt;
            &lt;/bean&gt;
        &lt;/property&gt;
	&lt;/bean&gt;
	
	&lt;!-- Gerenciador das transacoes dos servicos --&gt;
	&lt;bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"&gt;
		&lt;property name="entityManagerFactory" ref="entityManagerFactory" /&gt;
	&lt;/bean&gt;
	
	&lt;!--
		Indica ao spring que as transacoes serao demarcadas com anotacoes e
		aponta qual eh o gerenciador das transacoes
	--&gt;
	&lt;tx:annotation-driven transaction-manager="transactionManager" /&gt;
	
	&lt;context:component-scan base-package="com.monteirosti" /&gt;
	
&lt;/beans&gt;

O serviço:

@Transactional                      //org.springframework.transaction.annotation.Transactional
@Service( "productService" )  //org.springframework.stereotype.Service
public class ProductServiceBean implements ProductService {

	@PersistenceContext      // já tentei assim também e nada @PersistenceContext( unitName = "devlp" )
	private EntityManager em;

}

Bem, de antemão, obrigado pela ajuda, mas o que eu posso estar fazendo de errado para que o preenchimento dos objetos não esteja sendo feito?

Um abraço.

5 Respostas

maiconramones

bland sei que o tópico é antigo, mas você conseguiu corrigir esse problema? Se sim, como?

Estou tendo o mesmo problema.

Abraço

bland

Olá Maicon, tudo bem?

Foi muito bom você “reativar” este tópico, pois eu nem lembrava mais que esse tópico existia.

Bem, respondendo a sua pergunta, sim, consegui resolver sim. Para contextualizar, o Spring tem o seu gerenciamento dos beans, e, pelo que entendi após pesquisar bastante, o JSF 2.0 também. Ou seja, quando anotamos uma classe como [color=olive]@ManagedBean[/color], até o momento, o JSF 2 não consegue enxergar os beans do Spring implicitamente. Sendo assim, é necessário que você faça uma injeção utilizando uma outra anotação, a [color=olive]@ManagedProperty[/color] (do pacote [color=red]javax.faces.bean.ManagedProperty[/color]).

Pronto, essa foi a explicação da teoria. Na prática, eu criei um arquivo xml para os meus serviços (que serão gerenciados pelo Spring) e coloquei apenas isso:

&lt;context:annotation-config /&gt;
&lt;context:component-scan base-package="br.com.package.service.impl" /&gt;
&lt;aop:aspectj-autoproxy /&gt;

Ou seja, o pacote base para a busca dos serviços é a implementação desses serviços. E não as interfaces.
Já no meu ManagedBean ficou dessa forma:

@ManagedProperty( value = "#{productService}" )
private ProductService productService;

Com essa anotação, o JSF 2 enxerga que será feita uma “injeção explícita” ao bean no qual você está anotando. Essa anotação ([color=olive]@ManagedProperty[/color]) utiliza do padrão JavaBeans, sendo assim, será necessário ter o método set do seu serviço na sua classe ManagedBean. Observe que o parâmetro utiliza Expression Language, pois ele busca essa informação dentro da própria aplicação, algo como um repositório de beans, por exemplo (não sei o nome exatamente, mas a ideia é essa). E para que essa integração funcione corretamente é necessário colocar no faces-config.xml a seguinte linha:

&lt;application&gt;
   &lt;el-resolver&gt;org.springframework.web.jsf.el.SpringBeanFacesELResolver&lt;/el-resolver&gt;
&lt;/application&gt;

E, claro, configurar corretamente o seu web.xml. Acho que seja isso. Não me lembro de mais nenhum detalhe. Caso tenha mais dúvidas, posta aqui que tentarei te ajudar quando for possível.

Um grande abraço.

maiconramones

Opa, bland.

Fiz como você falou e funcionou.

Uma outra sacanagem que tinha utilizado para injetar as dependências era anotar o meu @ManagedBean também com @Controller mas ficava estranho ter duas anotações com o mesmo objetivo, ficava assim:

@ManagedBean(name="loginMB") @Controller @RequestScoped

E depois [color=olive]@Inject[/color] em cima da propriedade do ManagedBean para injetar os serviços…

Uma observação: [color=red]<aop:aspectj-autoproxy />[/color] não foi preciso colocar isso no xml, o que esse atributo faz?

bland

Maicon,

Abstraia essa linha. Foi um copy / paste que fiz. Irei até remover dos meus xml’s.

Quanto a solução, existem diversas. Essa que mostrei achei a mais simples.

E pelo que você falou, também, né?

Um grande abraço e bons códigos.

maiconramones

Valeu pela força Brother.

Abraço

Criado 23 de abril de 2010
Ultima resposta 25 de ago. de 2010
Respostas 5
Participantes 2