Vraptor + spring + hibernate: gerenciar session e transação pelo spring

9 respostas
mario.fts

Boa tarde

Seguindo o tutorial da FJ28, cheguei no capitulo da integração com spring, mas não consigo fazer o sistema funcionar mais desde que coloquei o controle de transação no spring.

seguem os códigos:

AppContext:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
	<tx:annotation-driven />
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="configLocation">
			<value>classpath:/hibernate.cfg.xml</value>
		</property>
	</bean>
</beans>
no web.xml, eu registrei um provider:
<context-param>
    	<param-name>br.com.caelum.vraptor.provider</param-name>
    	<param-value>br.com.caelum.goodbuy.provider.CustomProvider</param-value>
	</context-param>
código do provider:
public class CustomProvider extends SpringProvider {

	@Override
	protected void registerCustomComponents(ComponentRegistry registry) {
		registry.register(SessionCreator.class, SessionCreator.class);
		registry.register(SessionFactoryCreator.class, SessionFactoryCreator.class);
		registry.register(HibernateTransactionInterceptor.class, HibernateTransactionInterceptor.class);
	}

}
o dao:
@Component
public class ProdutoDao {

	private Session session;

	public ProdutoDao(Session session) {
		this.session = session;
	}

	@Transactional
	public void salva(Produto produto) {
		session.save(produto);
	}

	public List<Produto> listaTudo() {
		return this.session.createCriteria(Produto.class).list();
	}
...
}

e o controler;

@Resource
public class ProdutosController {

	private final ProdutoDao dao;
	private Result result;
	private Validator validator;

	public ProdutosController(ProdutoDao dao, Result result, Validator validator) {
		this.dao = dao;
		this.result = result;
		this.validator = validator;
	}

	@Get
	@Path("/produtos")
	public List<Produto> lista() {
		System.out.println("Rá");
		return dao.listaTudo();
	}
...
}
do jeito que está, na hora de chamar algum método do dao, da o seguinte erro:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.hibernate.SessionFactory] is defined: expected single matching bean but found 2: [br.com.caelum.vraptor.util.hibernate.SessionFactoryCreator, sessionFactory]

Ah, blz, é pq eu registrei um SessionFactory no spring e um no provider.
tirei o do provider, (SessionFactoryCreator), e deixei o do spring, pq ele é usado na criação do transactionManager.

ai o erro mudou para:

Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class br.com.caelum.goodbuy.dao.ProdutoDao]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
	at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:212)
        ...
        ...
Caused by: java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
	at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:718)
	at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:499)

Sim, blz, é pq o construtor recebe uma session, e ele não ta achando o contrutor sem argumentos. Mas essa session deveria ter sido injetada pelo spring, ou pelo vraptor.
Como resolver essa situação? vou ter que deixar os dados sendo gerenciados pelo spring e pelo vraptor ao mesmo tempo?

[]'s

9 Respostas

Lucas_Cavalcanti

qdo vc usa qqer coisa com AOP (segurança por exemplo) vc não pode usar injeção de dependências pelo construtor…

ao invés do construtor crie setters pros atributos e anote-os com @Autowired (do spring) e tudo vai funcionar

Lucas_Cavalcanti

e, claro, vc não pode ter o SessionFactoryCreator registrado…

possivelmente vc vá ter que receber a session do jeito do spring tb, pq ele faz coisas bizarras envolvendo threadLocals… o jeito do spring é via HibernateTemplate ou SessionFactoryUtils…

mario.fts

blz, vou testar usando spring puro nessa parte então.

Mas, antes disso, olhei os fontes da classe HibernateTransactionInterceptor, pelo que eu vi ele simplesmente abre e fecha a transação a cada request. Ele não faz operações de roolback? Por que esse era o motivo de querer utilizar o controlador do spring

Valeu pela resposta lucas!

Lucas_Cavalcanti

sim, ele fecha a transação a todo request, mas se der algum problema no meio do caminho ele dá rollback…

o source:
http://github.com/caelum/vraptor/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/util/hibernate/HibernateTransactionInterceptor.java

G

Lucas Cavalcanti:
sim, ele fecha a transação a todo request, mas se der algum problema no meio do caminho ele dá rollback…

o source:
http://github.com/caelum/vraptor/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/util/hibernate/HibernateTransactionInterceptor.java

Não deveriamos ter rollback apenas em runtime-exceptions?

Lucas_Cavalcanti

pq?

se vc está dentro de uma transação, e qualquer coisa dá errado, vc tem que desfazer tudo… esse é o conceito de transações… ou tudo dá certo, ou nada acontece

G

Lucas Cavalcanti:
pq?

se vc está dentro de uma transação, e qualquer coisa dá errado, vc tem que desfazer tudo… esse é o conceito de transações… ou tudo dá certo, ou nada acontece

Pensei nesse conceito por causa do JTA. Apenas é feito rollback em runtime-exceptions ou quando você anota alguma não-runtime com @ApplicationException(rollback=true),

Em EJB apenas runtimes são feitas rollback.

Lucas_Cavalcanti

a idéia é colocar transações onde elas fazem sentido… e onde elas fazem sentido, qqer erro é motivo de rollback

no caso de EJBs, tem muito mais coisa envolvida do que só a sua lógica de negócio, e assim talvez faça algum sentido não dar rollback em certos casos (não que eu concorde, mas…)

G

:thumbup:

Criado 12 de maio de 2010
Ultima resposta 12 de mai. de 2010
Respostas 9
Participantes 3