프로그래밍

[Spring] day64 : 2-Layerd 아키텍처 스타일 본문

자바/Spring

[Spring] day64 : 2-Layerd 아키텍처 스타일

시케 2023. 8. 14. 00:04
728x90
반응형

2023.08.08.화

2-Layerd 아키텍처 스타일

: 표현 계층과 비즈니스(핵심) 계층의 통합
: 프레젠테이션 레이어와 비즈니스 레이어의 통합

 

현재의 프로그램 작동 방식은 다음과 같다

1) 브라우저(Client, 사용자)에서 서버로 요청

2) DispatcherServlet 서블릿 생성 후 의존 주입
3) 요청에 맞는 Controller 객체를 호출하여 사용

해당 방식은 유지보수가 불리하며 AOP 적용이 불가하다

이를 해결하기 위해

표현 계층(프레젠테이션 레이어)/비즈니스 레이어를 사용하여 보자

 

더보기

※ 현재 유지보수 불리한 상태
※ 1) 서버에서는 DBMS 변경이 잦다
즉, DAO 변경 또한 잦다
"DAO"를 직접 이용하고 있기 때문에 결합도가 높아서 유지보수 불리
(객체를 직접 사용하면 결합도 증가)
다른 DAO로의 변경이 매우 불리한 상태

※ 2) AOP 적용이 불가한 상태
xxxService 류에만 호출 가능함
( AOP를 사용하면 로그, 보안, 권한 확인, ...등을 자동호출할 수 있음)
( 위의 코드를 별도로 분리해서 관리할 수 있음 -> 응집도 ↑)
( 유지보수가 유리 )
매번 로그, 보안, 권한 확인 등을 직접 처리해야 하므로 응집도 낮음
유지보수 불리

비즈니스 레이어 추가

DAO를 직접 사용하지 않고 Service가 대신 사용하게 할 것이다

 

1) C의 메서드 인자로 존재하던 DAO 제거
2) DAO를 대신 사용해줄 Service를 멤버변수로 추가

@Controller
public class BoardController {
	
	@Autowired
	private BoardService boardService;
	
    
	@RequestMapping(value="/board.do")
	public String selectBoard(BoardVO bVO, Model model) {
		System.out.println("BoardController 로그");
		model.addAttribute("data", boardService.selectOne(bVO));
		boardService.update(bVO);
		return "board.jsp";
	}
	
	@RequestMapping(value="/updateBoard.do")
	public String updateBoard(BoardVO bVO) {
		System.out.println("BoardController 로그");
		if(boardService.update(bVO)){
			return "redirect:main.do";
		}
		else{
			return "board.do";
		}
	}
	
	@RequestMapping(value="/deleteBoard.do")
	public String deleteBoard(BoardVO bVO) {
		System.out.println("BoardController 로그");
		if(boardService.delete(bVO)){
			return "redirect:main.do";
		}
		else{
			return "board.do";
		}
	}
	
	//
	@RequestMapping(value="/insertBoard.do", method=RequestMethod.GET)
	public String insertBoardPage() {
		System.out.println("InsertBoardPageController 로그");
		
		return "redirect:insertBoard.jsp";
	}
	
	@RequestMapping(value="/insertBoard.do", method=RequestMethod.POST)
	public String insertBoard(BoardVO bVO) {
		System.out.println("InsertBoardController 로그");
		
		if(boardService.insert(bVO)){
			return "redirect:main.do";
		}
		else{
			return "redirect:insertBoard.jsp";
		}
	}
	//
	
}

위의 코드를 보면 더 이상 BoardDAO가 사용되지 않는 것을 볼 수 있다

 

이젠 DAO가 변경되더라도 Service 내부의 멤버변수만 변경하면 된다
▶ 결합도가 낮아지므로 유지보수 유리

 

public interface BoardService {
	public BoardVO selectOne(BoardVO bVO);
	public List<BoardVO> selectAll(BoardVO bVO);
	
	public boolean insert(BoardVO bVO);
	public boolean update(BoardVO bVO);
	public boolean delete(BoardVO bVO);
}
package com.spring.biz.board;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("boardService")
public class BoardServiceImpl implements BoardService {
	// Service 레이어가 관념적으로 존재하는데, 그것을 구현한 클래스
	// Service 레이어에서는 DAO를 사용
	//  == C 파트
	//  : DAO를 사용할것이기 때문에
	//    DAO와 메서드 시그니처를 맞추면 유리
	// 메서드 시그니처를 강제를 위해 인터페이스 사용
	
	@Autowired
	private BoardDAO boardDAO;
	// 의존관계 -> DI
	
	@Override
	public BoardVO selectOne(BoardVO bVO) {
		return boardDAO.selectOne(bVO);
	}

	@Override
	public List<BoardVO> selectAll(BoardVO bVO) {
		return boardDAO.selectAll(bVO);
	}

	@Override
	public boolean insert(BoardVO bVO) {
		return boardDAO.insert(bVO);
	}

	@Override
	public boolean update(BoardVO bVO) {
		return boardDAO.update(bVO);
	}

	@Override
	public boolean delete(BoardVO bVO) {
		return boardDAO.delete(bVO);
	}
}

멤버변수로 추가한 Service가 메서드 수행 주체로써 사용되므로
의존관계 발생하여 DI(의존주입)을 해야한다
→ @Autowired

 

루트 컨테이너 설정

현재의 코드를 작동시 BeanCreateException이 발생할 것이다

이는 의존주입이 올바르게 되지 않아서이다

 

객체 생성 전에

즉, 메모리에 해당 자료형의 객체가 없는데 의존 주입을 시도하였기 때문에 발생한다

더보기

BoardController를 못 만들음
boardService 의존 주입 실패
-> 메모리에서 찾을 수 없음
-> 순서! 의존성 주입을 객체 생성보다 먼저 함

@Autowired

boardService 메모리에 없으며 이는 @Service가 동작하지 않았다는 뜻이다
이는 DispatcherServlet-servlet.xml에서 component-scan을 하지 않았기 때문이다

 

단순히 scan을 하도록 하는 방식도 있지만

이러한 경우를 미연에 방지하고자

서버가 시작될때 메모리에 객체가 생성되도록 할 것이다

특정한 시점에 특정한 기능을 넣고 싶으므로 리스너를 이용할 것이며

리스너를 통해 루트 컨테이너를 지정할 것이다

 

applicationContext.xml에서 미리 DAO, Service 류의 객체들을 생성한 뒤
web.xml로 DS 생성하며
DS-servlet.xml로 Controller를 호출할 수 있게 할 것이다

 

리스너는 NOT POJO이므로 web.xml에서 설정한다

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://Java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<servlet>
		<servlet-name>DispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>DispatcherServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

	<filter>
		<filter-name>characterEncoding</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter
		</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>characterEncoding</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>


	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

</web-app>

루트 컨테이너로써 "서버가 시작될때" applicationContext.xml을 구동시킨다

 

∴ 루트 컨테이너 (, 스프링 컨테이너, 비즈니스 레이어)가 객체들을 메모리에 new 한뒤
서블릿 컨테이너(web.xml)가 DS을 메모리에 new 한다
스프링 컨테이너(DS-servlet.xml, 프레젠테이션 레이어)가 Controller를 호출하여 요청을 처리한다
▷▷▷2-Layerd 아키텍처 스타일

 

https://github.com/jihyean/Spring/tree/main/day64

 

728x90
반응형
Comments