Java 기반 웹 애플리케이션 아키텍처를 공유하십시오!
Java를 사용하여 구현해야하는 웹 응용 프로그램을위한 다양한 아키텍처가 있습니다. 이 질문에 대한 답변은 장단점이있는 다양한 웹 응용 프로그램 디자인의 라이브러리 역할을 할 수 있습니다. 나는 그 대답이 주관적이라는 것을 알고 있지만, 가능한 한 객관적이되고 우리가 제시 한 장단점에 동기를 부여하도록합시다.
아키텍처를 설명하기 위해 원하는 세부 수준을 사용하십시오. 당신의 대답이 어떤 가치를 갖기 위해서는 최소한 당신이 묘사 한 아키텍처에 사용 된 주요 기술과 아이디어를 설명해야합니다. 마지막으로 아키텍처를 언제 사용해야합니까?
시작하겠습니다 ...
아키텍처 개요
Java EE, Java Persistence API, Servlet 및 Java Server Pages와 같은 Sun의 개방형 표준을 기반으로하는 3 계층 아키텍처를 사용합니다.
- 고집
- 사업
- 표시
계층 간 가능한 통신 흐름은 다음과 같이 표시됩니다.
Persistence <-> Business <-> Presentation
예를 들어, 프리젠 테이션 계층은 지속성 작업을 호출하거나 지속하지 않으며 항상 비즈니스 계층을 통해 수행합니다. 이 아키텍처는 고 가용성 웹 응용 프로그램의 요구를 충족시키기위한 것입니다.
고집
CRUD ( Create , Read, Update and Delete ) 지속성 작업을 수행합니다. 우리의 경우에는 ( Java Persistence API ) JPA를 사용하고 있으며 현재는 Hibernate 를 지속성 공급자로 사용 하고 EntityManager를 사용 합니다 .
이 계층은 여러 클래스로 구분되며, 각 클래스는 특정 유형의 엔티티 (예 : 장바구니 관련 엔티티가 단일 지속성 클래스에 의해 처리 될 수 있음)를 처리하며 하나의 관리자 만 사용 합니다 .
또한,이 층은 또한 저장 JPA 엔티티 것들처럼되어 Account
, ShoppingCart
등등
사업
웹 응용 프로그램 기능과 관련된 모든 논리는이 계층에 있습니다. 이 기능은 신용 카드를 사용하여 온라인으로 제품에 대한 비용을 지불하려는 고객에게 송금을 시작할 수 있습니다. 웹 기반 게임에서 새로운 사용자를 생성하거나 사용자를 삭제하거나 전투 결과를 계산할 수도 있습니다.
이 계층은 여러 클래스로 나뉘며 각 클래스에는 SLSB ( Stateless Session Bean)@Stateless
가되도록 주석이 달려 있습니다. 각 SLSB는 관리자 라고하며 , 예를 들어 관리자는 언급 된대로 주석이 달린 클래스 일 수 있습니다 .AccountManager
경우 AccountManager
요구 CRUD 작업을 수행 할 수는 인스턴스에 대한 적절한 호출하게 AccountManagerPersistence
지속 층의 클래스이다. 두 가지 방법의 대략적인 스케치는 AccountManager
다음과 같습니다.
...
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
}
우리가 사용하는 컨테이너 관리 트랜잭션을 우리는 트랜잭션 경계 우리 자기의 작업을 수행 할 필요가 없습니다. 기본적으로 발생하는 상황은 SLSB 메서드를 시작할 때 트랜잭션을 시작하고 메서드를 종료하기 직전에 커밋 (또는 롤백)하는 것입니다. 구성에 대한 관례의 예이지만 기본, 필수 이외의 다른 것은 필요하지 않았습니다.
다음은 Sun의 Java EE 5 Tutorial이 EJB (Enterprise JavaBeans) 의 필수 트랜잭션 속성 을 설명하는 방법입니다 .
클라이언트가 트랜잭션 내에서 실행 중이고 엔터프라이즈 Bean의 메소드를 호출하면 메소드는 클라이언트의 트랜잭션 내에서 실행됩니다. 클라이언트가 트랜잭션과 연결되어 있지 않으면 컨테이너는 메소드를 실행하기 전에 새 트랜잭션을 시작합니다.
필수 속성은 컨테이너 관리 트랜잭션 경계 설정으로 실행되는 모든 엔터프라이즈 Bean 메소드에 대한 내재적 트랜잭션 속성입니다. 다른 트랜잭션 속성을 대체하지 않으면 일반적으로 필수 속성을 설정하지 않습니다. 트랜잭션 속성은 선언적이므로 나중에 쉽게 변경할 수 있습니다.
표시
프레젠테이션 레이어는 ... 프레젠테이션을 담당합니다! 사용자 인터페이스를 담당하며 HTML 페이지를 작성하고 GET 및 POST 요청을 통해 사용자 입력을 수신하여 사용자에게 정보를 표시합니다. 우리는 현재 구 서블릿 + JSP (Java Server Pages ) 조합을 사용하고 있습니다.
계층 은 비즈니스 계층 관리자 에서 메소드를 호출 하여 사용자가 요청한 작업을 수행하고 웹 페이지에 표시 할 정보를 수신합니다. 때로는 비즈니스 계층으로부터 수신 된 정보는 덜 복잡한 종류 String
의와 int
egers, 그리고 다른 배에서 JPA 엔티티 .
아키텍처의 장단점
찬성
- 이 계층에서 지속성을 유지하는 특정 방법과 관련된 모든 것이 있다는 것은 비즈니스 계층에서 아무것도 다시 작성할 필요없이 JPA 사용에서 다른 것으로 바꿀 수 있다는 의미 일뿐입니다.
- 프리젠 테이션 레이어를 다른 것으로 쉽게 교체 할 수 있으며 더 나은 것을 찾게 될 것입니다.
- EJB 컨테이너가 트랜잭션 경계를 관리하게하는 것이 좋습니다.
- 서블릿의 + JPA를 사용하는 것은 쉬우 며 (처음부터) 기술은 많은 서버에서 널리 사용되고 구현됩니다.
- Java EE를 사용하면 로드 밸런싱 및 페일 오버 기능을 갖춘 고 가용성 시스템을보다 쉽게 만들 수 있습니다 . 둘 다 우리는 반드시 있어야한다고 느낍니다.
단점
- JPA를 사용
@NamedQuery
하면 JPA 엔터티 클래스 의 주석을 사용하여 자주 사용하는 쿼리를 명명 된 쿼리로 저장할 수 있습니다 . 아키텍처에서와 같이 지속성 클래스의 지속성과 관련이있는 경우 JPA 엔티티를 포함하는 쿼리를 찾을 수있는 위치가 분산됩니다. 지속성 작업을 개괄하기가 더 어려워 유지 관리가 더 어려워집니다. - 지속성 계층의 일부로 JPA 엔티티가 있습니다. 그러나
Account
하고ShoppingCart
, 그들은 정말 비즈니스 오브젝트 않나요? 이러한 클래스를 터치하고 JPA가 처리하는 방법을 알고있는 엔티티로 전환해야하므로이 방식으로 수행됩니다. - 비즈니스 오브젝트이기도 한 JPA 엔티티는 VO (Value Objects)라고도하는 DTO (Data Transfer Object)와 같이 작성 됩니다. 에서이 결과 빈혈 도메인 모델 비즈니스 객체로는 접근 방법을 제외하고 자신의 어떤 로직이 없습니다. 모든 로직은 비즈니스 계층의 관리자가 수행하므로보다 절차적인 프로그래밍 스타일이됩니다. 좋은 객체 지향 디자인은 아니지만 문제가되지 않을 수도 있습니다. (모든 객체 지향 이후 결과를 제공 한 유일한 프로그래밍 패러다임은 아닙니다.)
- EJB와 Java EE를 사용하면 약간의 복잡성이 발생합니다. 그리고 우리는 순수 Tomcat을 사용할 수 없습니다 (EJB 마이크로 컨테이너를 추가하는 것이 순전히 Tomcat 이 아닙니다 ).
- 서블릿 + JPA 사용과 관련된 많은 문제가 있습니다. 이러한 문제에 대한 자세한 내용을 보려면 Google을 사용하십시오.
- 비즈니스 계층을 종료 할 때 트랜잭션이 닫히
fetch=FetchType.LAZY
므로 프리젠 테이션 계층 내부에서 필요할 때 (사용 ) 데이터베이스에서로드되도록 구성된 JPA 엔티티의 정보를로드 할 수 없습니다 . 예외가 발생합니다. 이러한 종류의 필드가 포함 된 엔터티를 반환하기 전에 관련 getter를 호출해야합니다. 또 다른 옵션은 JPQL (Java Persistence Query Language)을 사용 하고을 수행하는 것FETCH JOIN
입니다. 그러나이 두 옵션은 약간 번거 롭습니다.