Vamos compartilhar arquiteturas de aplicativos da Web baseadas em Java!
Existem muitas arquiteturas diferentes para aplicativos da web que devem ser implementadas usando Java. As respostas a essa pergunta podem servir como uma biblioteca de vários designs de aplicativos da Web com seus prós e contras. Embora eu perceba que as respostas serão subjetivas, vamos tentar ser o mais objetivos possível e motivar os prós e os contras que listamos.
Use o nível de detalhe que você preferir para descrever sua arquitetura. Para que sua resposta seja de qualquer valor, você precisará pelo menos descrever as principais tecnologias e idéias usadas na arquitetura que descreve. E por último mas não menos importante, quando devemos usar sua arquitetura?
Vou começar...
Visão geral da arquitetura
Utilizamos uma arquitetura de três camadas com base nos padrões abertos da Sun, como Java EE, Java Persistence API, Servlet e Java Server Pages.
- Persistência
- O negócio
- Apresentação
Os possíveis fluxos de comunicação entre as camadas são representados por:
Persistence <-> Business <-> Presentation
O que, por exemplo, significa que a camada de apresentação nunca chama ou executa operações de persistência, mas sempre através da camada de negócios. Essa arquitetura destina-se a atender às demandas de um aplicativo da web de alta disponibilidade.
Persistência
Executa operações de persistência de criação, leitura, atualização e exclusão ( CRUD ). No nosso caso, estamos usando o JPA ( Java Persistence API ) e atualmente usamos o Hibernate como nosso provedor de persistência e usamos seu EntityManager .
Essa camada é dividida em várias classes, onde cada classe lida com um certo tipo de entidades (ou seja, entidades relacionadas a um carrinho de compras podem ser tratadas por uma única classe de persistência) e é usada por um e apenas um gerente .
Além disso, essa camada também armazena entidades JPAAccount
, como coisas ShoppingCart
etc.
O negócio
Toda a lógica vinculada à funcionalidade do aplicativo da web está localizada nessa camada. Essa funcionalidade pode estar iniciando uma transferência de dinheiro para um cliente que deseja pagar por um produto on-line usando seu cartão de crédito. Também poderia estar criando um novo usuário, excluindo um usuário ou calculando o resultado de uma batalha em um jogo baseado na Web.
Essa camada é dividida em várias classes e cada uma dessas classes é anotada @Stateless
para se tornar um SLSB ( Stateless Session Bean ). Cada SLSB é chamado de gerente e, por exemplo, um gerente pode ser uma classe anotada como mencionado AccountManager
.
Quando é AccountManager
necessário executar operações CRUD, ele faz as chamadas apropriadas para uma instância de AccountManagerPersistence
, que é uma classe na camada de persistência. Um esboço aproximado de dois métodos em AccountManager
poderia ser:
...
public void makeExpiredAccountsInactive() {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
// Calls persistence layer
List<Account> expiredAccounts = amp.getAllExpiredAccounts();
for(Account account : expiredAccounts) {
this.makeAccountInactive(account)
}
}
public void makeAccountInactive(Account account) {
AccountManagerPersistence amp = new AccountManagerPersistence(...)
account.deactivate();
amp.storeUpdatedAccount(account); // Calls persistence layer
}
Usamos transações de gerenciador de contêineres, para que não tenhamos que fazer a demarcação de transações. O que basicamente acontece sob o capô é que iniciamos uma transação ao entrar no método SLSB e a confirmamos (ou reverte-a) imediatamente antes de sair do método. É um exemplo de convenção sobre configuração, mas ainda não precisamos de nada além do padrão Obrigatório.
Aqui está como o Tutorial do Java EE 5 da Sun explica o atributo de transação Requerido para Enterprise JavaBeans (EJB's):
Se o cliente estiver executando dentro de uma transação e chamar o método do bean corporativo, o método será executado dentro da transação do cliente. Se o cliente não estiver associado a uma transação, o contêiner iniciará uma nova transação antes de executar o método.
O atributo Requerido é o atributo de transação implícita para todos os métodos de enterprise bean em execução com demarcação de transação gerenciada por contêiner. Normalmente, você não define o atributo Requerido, a menos que precise substituir outro atributo de transação. Como os atributos da transação são declarativos, você pode alterá-los facilmente mais tarde.
Apresentação
Nossa camada de apresentação é responsável por ... apresentação! Ele é responsável pela interface do usuário e mostra informações ao usuário criando páginas HTML e recebendo entrada do usuário por meio de solicitações GET e POST. Atualmente, estamos usando a antiga combinação Servlet + Java Server Pages ( JSP ).
A camada chama métodos nos gerentes da camada de negócios para executar operações solicitadas pelo usuário e receber informações para mostrar na página da web. Às vezes, as informações recebidas da camada de negócios são de tipos menos complexos como String
's' e ' int
egers ' e , outras vezes, entidades JPA .
Prós e contras da arquitetura
Prós
- Ter tudo relacionado a uma maneira específica de persistência nessa camada significa apenas que podemos mudar do JPA para outra coisa, sem precisar reescrever nada na camada de negócios.
- É fácil trocarmos nossa camada de apresentação por outra e é provável que o façamos se encontrarmos algo melhor.
- É bom deixar o contêiner EJB gerenciar limites de transação.
- O uso do Servlet + JPA é fácil (para começar) e as tecnologias são amplamente usadas e implementadas em muitos servidores.
- O uso do Java EE deve facilitar a criação de um sistema de alta disponibilidade com balanceamento de carga e failover . Ambos sentimos que devemos ter.
Contras
- Usando o JPA, você pode armazenar consultas frequentemente usadas como consultas nomeadas, usando a
@NamedQuery
anotação na classe de entidade JPA. Se você tiver o máximo possível de persistência nas classes de persistência, como em nossa arquitetura, isso espalhará os locais onde você poderá encontrar consultas para incluir também as entidades JPA. Será mais difícil visualizar as operações de persistência e, portanto, mais difíceis de manter. - Temos entidades JPA como parte de nossa camada de persistência. Mas
Account
eShoppingCart
eles não são realmente objetos de negócios? Isso é feito assim que você precisa tocar nessas classes e transformá-las em entidades com as quais a JPA sabe lidar. - As entidades JPA, que também são nossos objetos de negócios, são criadas como objetos de transferência de dados ( DTOs ), também conhecidos como objetos de valor (VOs). Isso resulta em um modelo de domínio anêmico, pois os objetos de negócios não têm lógica própria, exceto métodos de acessador. Toda a lógica é feita por nossos gerentes na camada de negócios, o que resulta em um estilo de programação mais processual. Não é um bom design orientado a objetos, mas talvez isso não seja um problema? (Afinal, a orientação a objetos não é o único paradigma de programação que produziu resultados.)
- O uso de EJB e Java EE apresenta um pouco de complexidade. E não podemos usar o Tomcat puramente (adicionar um micro-contêiner EJB não é puramente o Tomcat).
- Existem muitos problemas com o uso do Servlet + JPA. Use o Google para obter mais informações sobre esses problemas.
- Como as transações são fechadas ao sair da camada de negócios, não podemos carregar nenhuma informação das entidades JPA configuradas para serem carregadas do banco de dados quando necessário (usando
fetch=FetchType.LAZY
) de dentro da camada de apresentação. Isso acionará uma exceção. Antes de retornar uma entidade que contém esses tipos de campos, precisamos chamar os getter relevantes. Outra opção é usar o Java Persistence Query Language ( JPQL ) e executar umFETCH JOIN
. No entanto, essas duas opções são um pouco complicadas.
fonte
Respostas:
Ok, eu vou fazer um (mais curto):
Utilizamos o suporte a transações Sping e iniciamos transações ao entrar na camada de serviço, propagando-se para as chamadas do DAO. A camada de Serviço possui o maior conhecimento do modelo de negócios, e os DAO fazem trabalhos CRUD relativamente simples.
Algumas coisas de consulta mais complicadas são tratadas por consultas mais complicadas no back-end por razões de desempenho.
As vantagens de usar o Spring no nosso caso é que podemos ter instâncias dependentes do país / idioma, que estão por trás de uma classe Spring Proxy. Com base no usuário da sessão, a implementação correta do país / idioma é usada ao fazer uma chamada.
O gerenciamento de transações é quase transparente, com reversão nas exceções de tempo de execução. Usamos exceções não verificadas o máximo possível. Costumávamos fazer exceções verificadas, mas com a introdução do Spring, vejo os benefícios de exceções não verificadas, lidando apenas com exceções quando é possível. Evita muitas coisas clichê de "pegar / reler" ou "joga".
Desculpe, é mais curto que o seu post, espero que você ache isso interessante ...
fonte
Hoje, as tecnologias ideais de desenvolvimento da Web baseadas em Java.
Camada da Web:
HTML + CSS + Ajax + JQuery
Controlador da Web RESTFul / Camada de processamento de ação / solicitação:
Play Framework
Lógica comercial / camada de serviço:
Use o código Java puro o maior tempo possível. Pode-se fazer a fusão de serviços da web aqui.
Camada de transformação de dados XML / JSon:
XMLTool (pesquisar no código do Google), JSoup, Google GSon, XStream, JOOX (pesquisar no código do Google)
Camada de persistência:
CRUD: JPA ou SienaProject ou QueryDSL / consultas complexas: JOOQ, QueryDSL
fonte
Aqui estão os meus 5 centavos
Apresentação
Android, Angular.JS WebClient, OAUTHv2
API
REST, Jersey (JAX-RS), Jackson (descriptografia / serialização JSON), objetos DTO (diferentes dos modelos de lógica de negócios)
Logíca de negócios
Mola para DI e manipulação de eventos. Abordagem DDD-ish de objetos de modelo. Os trabalhos em execução mais longos são transferidos com o SQS nos módulos de trabalho.
DAO
Modelo de repositório com modelos JDBC do Spring para armazenar Entidades. Redis (JEDIS) para tabelas de classificação, usando listas ordenadas. Memcache para Token Store.
Base de dados
MySQL, Memcached, Redis
fonte
O que seguimos em nosso projeto é:
Tecnologia de front-end
API
Logíca de negócios
DADOS DA PRIMAVERA
Dados do SPRING MongoDB
Base de dados
Servidor (para armazenamento em cache)
fonte
Ainda estamos usando a pilha Struts-Spring-Hibernate usual.
Para aplicativos futuros, analisamos o Spring Web Flow + Spring MVC + Hibernate ou Spring + Hibernate + Web Services com o front end Flex.
Uma característica distinta da nossa arquitetura é a modularização. Temos vários módulos, alguns começando com 3 a no máximo 30 tabelas no banco de dados. A maioria dos módulos consiste em negócios e projeto web. Projeto de negócios mantém lógica de negócios e persistência, enquanto a web mantém lógica de apresentação.
No nível lógico, existem três camadas: Negócios, Persistência e Apresentação.
Dependências: A
apresentação depende dos negócios e da persistência.
A persistência depende dos negócios.
Os negócios não dependem de outras camadas.
A maioria dos projetos de negócios possui três tipos de interfaces (nota: não GUI, é uma camada de interface java programática).
Freqüentemente, 1 estende 2. Dessa forma, é fácil substituir uma implementação do módulo por outra. Isso nos ajuda a adotar diferentes clientes e a integrar mais facilmente. Alguns clientes compram apenas determinados módulos e precisamos integrar a funcionalidade que eles já possuem. Como a interface e a camada de implementação são separadas, é fácil implementar a implementação do módulo ad-hock para esse cliente específico sem afetar os módulos dependentes. E o Spring Framework facilita a injeção de diferentes implementações.
Nossa camada de negócios é baseada em POJOs. Uma tendência que estou observando é que esses POJOs se parecem com DTOs. Sofremos com o modelo de domínio anêmico . Não sei ao certo por que isso está acontecendo, mas pode ser devido à simplicidade do domínio do problema de muitos de nossos módulos, a maior parte do trabalho é CRUD ou porque os desenvolvedores preferem colocar a lógica em outro lugar.
fonte
Aqui está mais uma arquitetura da web em que trabalhei:
Camada de apresentação:
Web para dispositivos móveis (HTML5 / CSS3 / design responsivo)
Controladores REST de mola (pode mudar para JAX-RS)
Nível de serviço comercial:
Spring @Service (pode mudar para EJB sem estado)
Camada de acesso a dados:
Spring @Repository (pode mudar para EJB sem estado)
Camada de Recursos:
Entidades de hibernação (JPA) (podem mudar para qualquer ORM)
Você pode encontrar mais informações no livro que segue essa arquitetura aqui .
fonte
IMHO, a maioria de nós tem um denominador comum. Pelo menos no back-end, temos alguma forma de contêiner IOC / DI e uma estrutura de persistência. Pessoalmente, uso Guice e Mybatis para isso. As diferenças estão em como implementamos a camada de visualização / interface do usuário / apresentação. Existem 2 opções principais aqui (podem ser mais). Baseado em ação (URLs mapeados para controladores) e baseado em componente. Atualmente, estou usando a camada de apresentação baseada em componentes (usando o wicket). Imita perfeitamente um ambiente de área de trabalho onde eu uso componentes e eventos em vez de URLs e controladores. Atualmente, estou procurando um motivo para migrar para esse tipo de arquitetura de controlador de URL (foi assim que acabei nesta página). Por que o hype sobre as arquiteturas RESTful e Stateless.
Para responder a essa pergunta em resumo: escrevo aplicativos da Web com estado usando uma estrutura orientada a componentes em cima do contêiner do Guice IOC e coloco dados no banco de dados relacional usando Mybatis.
fonte
Um pouco diferente, e eu reivindicaria uma arquitetura java mais modular aqui. Nós temos:
Além do acima, temos os módulos de biblioteca compartilhada, que é um provedor de funcionalidade comum para todos os serviços.
O uso de diferentes camadas nos permite dissociar completamente e a modularidade de que precisamos. Também podemos utilizar totalmente o poder do Java EE e do Spring. Nada nos impede de usar o JSF, por exemplo, para o front end, se necessário.
Comparado ao exemplo de arquitetura do OP, acho que isso pode ser descrito como tendo quatro camadas principais em vez de três, embora com um toque.
fonte
Eu trabalhei em projetos que usam esse padrão rígido de gerente. Historicamente, eu era um grande defensor da hierarquia rígida, onde tudo se encaixava em uma caixa organizada. À medida que progrido na minha carreira, acho que isso é forçado em muitos casos. Acredito que adotar uma mentalidade mais ágil em relação ao design de aplicativos leva a um produto melhor. O que quero dizer com isso é criar um conjunto de classes que resolva o problema em questão. Em vez de dizer "Você criou um gerente para isso e aquilo?"
O projeto atual em que estou trabalhando é um aplicativo Web com uma combinação de chamadas Spring MVC e RestEasy JSON / Ajax. No lado do servidor incorporado em nossos controladores, há uma camada de dados sensível à fachada com JPA / Hibernate para acesso direto ao banco de dados, algum acesso EJB e algumas chamadas de serviço da Web baseadas em SOAP. Juntando tudo isso, há um código de controlador java personalizado que determina o que serializar como JSON e retornar ao cliente.
Nós gastamos quase nenhum tempo tentando criar algum padrão unificado, optando por adotar a idéia "Pior é Melhor" da Filosofia do Design Unix. Sendo muito melhor colorir fora das linhas e criar algo sensível, mais rápido do que criar algo que atenda a vários requisitos estritos de design.
fonte
Os componentes na arquitetura de aplicativos da Web incluem:
1: Navegador: interação com o cliente
2: Internet
3: servidor da Web
4: Servidor de Aplicativos
5: servidor de banco de dados
6: Dados
fonte