Arquitetura aplicação com Struts 2 + Spring 2 + Hibernate

Galera, estou com uma grande dúvida e preciso da opnião de vocês. É o seguinte, estou aproveitando um trabalho da faculdade para aplicar struts 2. Então esses dias estava fazendo um tutorial que mostra a inetgração de strtus 2 + spring 2 + hibernate, porém por ser apenas um exemplo simples a arquitetura do sistema está muito falha.

Então gostaria de saber de vocês como deve ser a arquitetura de uma aplicação utilizando essas tecnologias:
Struts 2: MVC
Spring 2: controle de transações e injeção de dependencia
Hibernate: persistencia

Alguem sabe?

Na empresa o qual trabalho usamos struts 1 e hibernate com o seguinte fluxo:

UI -> UsuarioAction -> fachada -> CadastroUsuario-> RepositorioUsuario ->banco
ainda existem: UsuarioBO e UsuarioForm.

onde:
1 - Repositorio: é um singleton que conversa direto com o banco de dados (inserir, alterar, consultar…).
2 - Cadastro: é um singleton que contem uma referencia ao repositorio(IRepositorioUsuario) correspondente e onde são implementadas as validações de regras de negócio.
3 - Fachada: é um singleton que contem uma referencia a cada classe Cadastro e apenas chama o método do cadastro direto (acho que se chama delegate).
4 - UsuarioBO: basicamente a representação dos campos da entidade, são usados para serem mapeados pelo hibernate e portanto, persistidos.

Bem, não tenho experiencia com padrões de projeto mas to querendo aprender algo a respeito com esse trabalho, por isso estou querendo utilizar todas essas tecnologias, portanto…não me digam pra usar algo mais simples…

conto com a ajuda de vocês pessoal.

vai usar JPA?
só uma pergunta, porque tantos singletons na sua arquitetura???

uso mais ou menos as mesma tecnologias que vc citou, a diferença é que eu uso jpa…
faço assim:

tela -> action,pojo… (struts2) -> bussiness (factory usando reflection) e é nela que é injetado o entity manager -> services (incluir, excluir, alterar… etc) passo para ela meu entity manager que foi injetado na camada bussiness para executar as operações e também fiz um esquema de composite para executar outras tarefas que saim do crud basico…

abs!!!

Eu vou usar o Hibernate né…que acaba sendo implementação de JPA.

Quanto aos singletons, não fui eu que defini…é a arquitetura usada no trabalho…mas acredito que seja pq essas classes não tem necessidade de serem instanciadas toda hora…não sei te explicar ao certo…mas enfim…

fiquei com algumas dúvidas:

Como o seu Action acessa o bussiness? o Action tem uma referencia a esse objeto é?

Pq seu entity manager não é injetado direto no Service? Você usa ele pra fazer algo no seu bussiness?

E só pra confirmar, tuas validações de regra de negócio são feitas no bussiness, certo?

Agora, se sua arquitetura não tem uma fachada, se você precisar manipular mais de uma entidade numa operação, você usa o bussiness dessa outra entidade direto no seu bussiness atual?

fico no aguardo!
flw

É que você pode usar Hibernate sem usar JPA, foi por isso que eu perguntei…

a Action acessa a camada bussiness usando uma Factory de objetos bussiness, a minha action só tem a interface, a classe implementada é a factory que me retorna.

Bom, isso é uma longa discussão, varias pessoas tem opiniões diferentes sobre isso, EU não concordo em colocar o meu entity manager na camada services porque na MINHA OPINIÃO o controle transacional deve ser feito na camada de negocio, onde eu posso fazer vários inserts, updates, deletes e etc e só depois que sair dessa camada, a app executa o commit ou se der algum erro efetua o roolback. Só para não alimentar alguns throlls, gostaria de deixar claro que oque eu acabei de falar é a minha opinião, não vão estragar a thread desvirtuando o assunto principal do marlon patrick.

sim, validações de REGRA DE NEGOCIO ficam no bussiness, isso msm.

Sim, por convenção (minha convenção) sei que somente as actions podem chamar as classes bussiness e uma bussiness pode chamar quantas outras bussiness forem necessárias ( contanto que esteja no escopo dessa classe e faça sentido, pois caso não faça, volto para a action e chamo outra bussiness. Só para fechar, uma bussiness pode chamar quantas outras bussiness quiser e uma action pode chamar quantas bussiness quiser.

Espero ter ajudado, qq coisa é só falar.

abs!!!

Então pelo que entendi o seu Business = meu Cadastro e o teu Service = meu Repositorio.

Cara, vlw…deu pra esclarecer…minha arquitetura não vai ficar igual a sua só por conta que a minha tem fachada e a tua não…
mas eu prefiro assim…acho que é uma forma de centralizar todos esses métodos que acessam banco de dados.

Decide que vou manter a Fachada e os Cadastros como singletons via código mesmo…e os meus Repositorios serão singletons também, porém o Spring é quem vai controlar isso…pois vou usar injeção de dependencia pra injetar o repositorio no cadastro. Acho que é o unico lugar que faz sentido usar DI, pois não vejo pq haveria uma mudança de implementação da Fachada (que só faz delegar) e também dos cadastros, fazendo assim com que eu não me preocupe tanto com acoplamento nessas camadas, o que é totalmente diferente no Repositorio, pois pode haver necessidade de mudar de banco e etc.

Ah, e pra ficar respondido mesmo vou usar JPA…to aproveitando pra fazer muitas experiencias nesse trabalho…até mesmo pra aprender então vou usar sim…

inclusive…me tire uma duvida quanto a isso…

quando eu uso meu EntityManger para, por exemplo, da um insert…eu não preciso usar um “commit” e é como se ele já fizesse isso automaticamente…como posso mudar isso…tipo um autoCommit = false?

humm, certo…
esse comportamento é devido a anotação @Transactional na classe que será injetado o entity manager.

para você controlar a sua transação manualmente ( lembrando que isso é perigoso, e eu não vejo um motivo a não ser em casos muito específicos para fazer isso ) deve fazer mais ou menos assim:

EntityManager em = emf.getEntityManager();
EntityTransaction tx = em.getTransaction();
try
{
    tx.begin();
    
    //codigos..........
    
    tx.commit();
}
finally
{
    if (tx.isActive())
    {
        tx.rollback();
    }
}
em.close();

onde o objeto emf é do tipo EntityManagerFactory.
dessa maneira você vai conseguir controlar sua transação local manualmente que é igual a autoCommit = false, como você havia falado.

qq coisa só falar!

abs

certo…entendo que pode ser perigoso o controle manual…

mas tipo…e se ocorrer o que eu disse antes…tu da um insert…depois vai manipular alguma coisa…e da um erro…no exemplo que tenho aqui…ele não deu o rollback…essa é minha preocupação…segue:

@Transactional
public class PersonServiceImpl implements PersonService {

	private EntityManager entityManager;
	
	public EntityManager getEntityManager() {
		return entityManager;
	}
	
	@PersistenceContext
	public void setEntityManager(EntityManager entityManeger) {
		this.entityManager = entityManeger;
	}

    public List<Person> findAll() {
        Query query = getEntityManager().createQuery("select p FROM Person p");
        return query.getResultList();
    }

    public void save(Person person){
        entityManager.persist(person);
    }

    public void update(Person person) {
    	entityManager.merge(person);        
    }

    public void remove(long id) {
        Person person = find(id);
        if (person != null) {
            entityManager.remove(person);
        }
    }
    
    public Person find(long id) {
        return entityManager.find(Person.class, id);
    }


}
<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
	
	<bean id="personService" class="service.PersonServiceImpl" scope="singleton"/>
	
	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="database" value="MYSQL" />
				<property name="showSql" value="true" />
			</bean>
		</property>
	</bean>
	
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/teste" />
		<property name="username" value="root" />
		<property name="password" value="senha" />
	</bean>
	
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	
	<tx:annotation-driven transaction-manager="transactionManager" />
	
	<bean id="PersonAction" scope="prototype" class="action.PersonAction">
		<constructor-arg ref="personService" />
	</bean>
</beans>

[quote=marlon patrick]certo…entendo que pode ser perigoso o controle manual…

mas tipo…e se ocorrer o que eu disse antes…tu da um insert…depois vai manipular alguma coisa…e da um erro…no exemplo que tenho aqui…ele não deu o rollback…essa é minha preocupação…
[/quote]

Acho que o problema é que você não está entendendo a lógica de quando e como e quando é efetuado um roolback, vou tentar te explicar:

Quando você deixa a transação por conta do Spring, o roolback só sera efetuado quando ocorrer alguma exception do tipo PersistenceException ou suas filhas, repare que essa exception é do tipo “não checada”, estende de RuntimeException. No mais, a transação será comitada sim, pois pela logica, não ocorreu um erro no tramite de persistência, e sim um outro erro qualquer que não está relacionado com a persistência dos dados em si.
Um excelente link que explica bastante coisas sobre transações usando jpa + spring é ESSE é uma ótima fonte de informações, mas caso encontre alguma dificuldade ou não entendeu direito o que eu expliquei, pergunte a vontade!

abs

Estranho…
acho que a transação deve ser comitada no action…
depois que vc fizer todas as logicas e acessos ao banco…
como ultima instrução do método no action.

Assim, caso ocorra após a operação realixada no banco…o mesmo possa dar rollback…

acho que no meu caso vou ter que fazer um controle manual mesmo…

vlw

Se achar trabalhosa a configuração do Spring com Struts2 só por causa das transações, pode optar pelo uso do Full Hibarnte Plugin
(http://cwiki.apache.org/S2PLUGINS/full-hibernate-plugin.html) que injeta Sessões e Transações Hibernate e as commita automaticmante após as requisições pra você. Praticamente zero configuração.