[Spring] 프레젠테이션 레이어와 비즈니스 레이어 통합, 검색 기능

2020. 8. 5. 02:51Spring/Spring

1. 비즈니스 컴포넌트

1) 프로그램 구조와 실행 순서

지금까지 클라이언트로 부터의 요청은 서블릿 컨테이너가 생성한 DispatcherServlet이 받고, 스프링 컨테이너가 생성한 Controller에게 요청을 전달 하고 DAO 객체를 이용하여 처리를한다. 이러한 구조와 실행 순서는 큰 문제가 없지만, Controller가 DAO 객체를 직접 접근해서는 안되고 반드시 비즈니스 컴포넌트를 이용해야한다.

프로그램 구조와 실행 순서 도식화

2) 비즈니스 컴포넌트 사용 이유

지금까지 게시판을 구현하면서 BoardService와 BoardServiceImpl 클래스를 사용하지 않고, BoardVO와 BoardDAO 클래스만 사용해왔다. Controller는 비즈니스 컴포넌트를 이용하여 사용자의 요청을 처리하고 컴포넌트가 제공하는 Service 인터페이스를 사용해야한다. 즉, Controller가 직접 DAO 클래스를 사용하지 않도록 해야한다.

 

만약, Controller가 직접 사용하게 될 경우, DAO 클래스 변경 시 유지보수면에서 효율적으로 관리하기 어렵다. 다른 DAO 클래스로 변경하거나 DAO 클래스를 이용하는 Controller가 여러 개일 경우 매개 변수를 일일이 수정해야한다. 결국, 비즈니스 컴포넌트가 수정이 되더라도 Controller가 수정 되지 않아야 한다.

 

비즈니스 컴포넌트를 사용하는 건 Controller이다. 클라이언트가 인터페이스를 통해서 비즈니스 컴포넌트를 이용하면 컴포넌트의 구현 클래스를 수정하거나 다른 클래스로 대체해도 이를 사용하는 클라이언트는 수정하지 않아도 된다(다형성).

/src/main/java/
BoardController.java

BoardController.java

BoardDAO를 다른 DAO 클래스로 쉽게 변경할 수 있다. 이럴 경우, BoardController를 수정하지 않아도 된다.

/src/main/java/
BoardServiceImpl.java

BoardServiceImpl.java

3) AOP 설정

Controller에서 DAO 메서드를 호출하면 안되는 이유는 AOP 적용의 문제도 있다. 지금까지의 개발은 포인트컷 설정 시 DAO 클래스의 메서드를 지정하는 것이 아닌 Service를 구현한 BoardServiceImpl 클래스의 메서드에 설정해왔다. 즉, 모든 어드바이스는 반드시 비즈니스 클래스의 메서드가 호출될 때 동작한다.

@Pointcut("execution(* com.springbook.biz..*Impl.*(..))" />

일반적으로 비즈니스 컴포넌트는 인터페이스를 가지고 있고, 해당 인터페이스만 컴포넌트를 사용하는 클라이언트에 노출한다. 비즈니스 컴포넌트를 사용하는 클라이언트는 인터페이스의 추상 메서드를 호출하여 인터페이스를 구현한 Service 구현 객체의 메서드를 실행할 수 있다. 결국, Controller 클래스는 비즈니스 컴포넌트의 인터페이스 타입의 멤버 변수를 가지고 있어야하며, 이 변수에 비즈니스 객체를 의존성 주입해야한다.

/src/main/java/
BoardController.java

BoardController.java

4) 비즈니스 컴포넌트 의존성 주입 문제

현재 구현된 코드에서는 presentation-layer.xml 파일에서 Controller 패키지에 대해 컴포넌트 스캔을 진행하기 때문에 BoardController만 생성이 된다. 클라이언트의 요청에 의해 서블릿 컨테이너는 DispatcherServlet을 생성하고 presentation-layer.xml을 로드한 뒤, 스프링 컨테이너에서 컴포넌트 스캔에 걸린 객체를 생성하게 되는데, presentation-layer.xml에 의해 BoardController 객체만 생성이 된다.

 

프로그램 실행 시, 앞서 BoarderController에 비즈니스 컴포넌트 구현을 위해 설정한 boarderService 변수에 의해 에러가 발생한다. boarderService 타입은 BoardService 타입의 객체가 메모리에 없어서 의존성 주입을 할 수 없게 된다. 즉, BoardService 인터페이스를 구현한 BoarderServiceImpl 객체가 메모리에 존재해야한다.

 

이 문제를 해결하기 위해서는 Controller 보다 의존성 주입 대상이 되는 비즈니스 컴포넌트를 먼저 생성해야한다. 즉, 비즈니스 컴포넌트를 먼저 생성하는 또 다른 스프링 컨테이너가 필요해진다.

의존성 주입 문제 도식화

※ @Autowired 어노테이션으로 선언된 변수를 의존성 주입할 때, 반드시 메모리에 변수의 타입에 해당하는 객체가 반드시 존재해야한다.

 

5) 2-Layered 아키텍처, ContextLoaderListener

비즈니스 컴포넌트를 먼저 생성하는 또 다른 스프링 컨테이너의 필요성으로 나온 아키텍처이다. 지금까지 설정 파일은  /src/main/resources/applicationContext.xml과 /WEB-INF/config/presentation-layer.xml 두 개가 있다. DispatcherServlet이 생성되어 presentation-layer.xml 파일을 읽고 스프링을 구동하면 Controller 객체가 생성이 된다. 하지만 Controller 객체가 생성하기 전에 applicationContext.xml 파일을 읽어 미리 생성해야한다. 따라서 먼저 생성할 수 있도록 스프링에서 ContextLoaderListener 클래스를 제공한다.

2-Layered 아키텍처 구조

ContextLoaderListener는 기본적으로 /WEB-INF/applicationContext.xml 파일을 읽어 스프링 컨테이너를 구동하기 때문에 applicationContext.xml 파일의 위치를 변경해야한다. 하지만 기본적으로 개발을 진행할 때, 유지보수 과정에서 비즈니스 컴포넌트를 수정하고 테스트를 진행하기 위해서 /src/main/resouces 소스 폴더에 위치시켜야 한다. (/src/test/java 소스 폴더에서 테스트 클라이언트 프로그램을 실행할 수 있다.)

 

스프링 설정파일을 /src/main/resources 소스 폴더에서 ContextLoaderListener가 읽어들일 수 있도록 <context-param>설정을 해야한다.

/src/main/webapp/WEB-INF/
web.xml

web.xml
스프링 컨테이너 동작 과정

 

 

 

2. 검색 기능

1) Command 객체 추가

/src/main/java/
BoardVO.java

BoardVO.java

2) Controller 수정

/src/main/java/
BoardController.java

BoardController.java

3) DAO 수정

/src/main/java/
BoardDAO.java

BoardDAO.java

4) Spring JDBC 수정

/src/main/java/
BoardDAOSpring.java

BoardDAOSpring.java


[참고] 스프링 퀵 스타트

728x90

'Spring > Spring' 카테고리의 다른 글

[Spring] 다국어 설정 (1)  (0) 2020.08.05
[Spring] 파일 업로드, 예외 처리  (0) 2020.08.05
[Spring] 어노테이션 MVC 구조  (0) 2020.08.03
[Spring] 스프링 MVC 구조  (0) 2020.08.03