Part 9. 비즈니스 계층
- 비즈니스 계층은 고객의 요구사항을 반영하는 계층으로 프레젠테이션 계층과 영속 계층의 중간 다리 역할을 하게 된다.
- 영속 계층은 데이터베이스를 기준으로 해서 설계를 나눠 구현하지만, 비즈니스 계층은 로직을 기준으로 해서 처리한다.
- 예컨대, '쇼핑몰에서 상품을 구매한다.'고 가정했을 때, 해당 쇼핑몰의 로직이 '물건을 구매한 회원에게는 포인트를 올려준다.'고 하면 역속 계층의 설게는 '상품'과 '회원'으로 나누어서 설계하게 된다.
- 반면에 비즈니스 계층은 상품 영역과 회원 영역을 동시에 사용해 하나의 로직을 처리하게 되므로 다음과 같은 구조를 만들게 된다.

- 현재 예제는 단일한 테이블을 이용하고 있기 때문에 위와 같은 구조는 아니지만, 설계를 할 때 원칙적으로 영역을 구분해 작성해야 한다.
- 일반적으로 비즈니스 영역에 있는 객체들은 '서비스(Service)'라는 용어를 많이 사용한다.
9.1 비즈니스 계층의 설정
- 비즈니스 계층을 위해 프로젝트 내 org.zerock.service 라는 패키지를 작성한다.

- 설계를 할 때 각 계층 간의 연결은 인터페이스를 이용해서 느슨한(loose) 연결을 한다.
- 게시물은 BoardService 인터페이스와 인터페이스를 구현한 BoardServiceImpl 클래스를 선언한다.

< BoardService 인터페이스 >
package org.zerock.service;
import java.util.List;
import org.zerock.domain.BoardVO;
public interface BoardService {
public void register(BoardVO board);
public BoardVO get(Long bno);
public boolean modify(BoardVO board);
public boolean remove(Long bno);
public List<BoardVO> getList();
}
- BoardService 메서드를 설계할 때 메서드 이름은 현실적인 로직의 이름을 붙이는 것이 관례다.
- 명백하게 반환해야 할 데이터가 있는 'select'를 해야 하는 메서드는 리턴 타입을 지정할 수 있다.
- 게시물은 특정한 게시물을 가져오는 get() 메서드와 전체 리스트를 구하는 getList()의 경우 처음부터 메서드의 리턴 타입을 결정해서 진행할 수 있다.
- BoardService 인터페이스를 구현하는 구현체는 BoardServiceImpl이라는 클래스로 작성한다.
< BoardServiceImpl 클래스 >
package org.zerock.service;
import java.util.List;
import org.springframework.stereotype.Service;
import org.zerock.domain.BoardVO;
import org.zerock.mapper.BoardMapper;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;
@Log4j
@Service
@AllArgsConstructor
public class BoardServiceImpl implements BoardService {
//spring 4.3 이상에서 자동 처리
private BoardMapper mapper;
@Override
public void register(BoardVO board) {}
@Override
public BoardVO get(Long bno) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean modify(BoardVO board) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean remove(Long bno) {
// TODO Auto-generated method stub
return false;
}
@Override
public List<BoardVO> getList() {
// TODO Auto-generated method stub
return null;
}
}
- BoardSErviceImpl 클래스에 가장 중요한 부분은 @Service라는 어노테이션이다.
- @Service는 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용한다.
- 작성된 어노테이션은 패키지를 읽어 들이는 동안 처리된다.
- BoardServiceImpl가 정상적으로 동작하기 위해 BoardMapper 객체가 필요하다.
- 이는 @Autowired와 같이 직접 설정해 줄 수 있고, Setter를 이용해 처리할 수도 있다.
- Lombok을 이요한다면 아래와 같은 방식으로 만들 수도 있다.
@Log4j
@Service
public class BoardServiceImpl implements BoardService {
@Setter(onMethod_ = @Autowired)
private BoardMapper mapper;
...
- 스프링 4.3부터는 단일 파라미터를 받는 생성자의 경우에는 필요한 파라미터를 자동으로 주입할 수 있다.
- @AllArgsConstructor는 모든 파라미터를 이요하는 생성자를 만들기 때문에 실제 코드는 아래와 같이 BoardMapper를 주입받는 생성자가 만들어지게 된다.

- 프로젝트 구조에서 클래스를 조사해 보면 스프링 4.3의 자동주입 기능으로 인해 위의 그림과 같은 형태가 된다.
9.1.1 스프링의 서비스 객체 설정(root-conetxt.xml)
- 비즈니스 계층의 인터페이스와 구현 클래스가 작성되었다면, 이를 스프링의 빈으로 인식하기 위해 root-context.xml에 @Service 어노테이션이 있는 org.zerock.service 패키지를 스캔하도록 추가해야 한다.
- 프로젝트 생성 시 만들어진 root-context.xml의 네임스페이스 탭에서 context 항목을 추가한다.

- 네임스페이스를 추가하면 해당 이름으로 시작하는 태그들을 활용할 수 있다.
- root-context.xml의 내부에 아래 내용을 추가한다.
< root-context.xml >
<context:component-scan base-package="org.zerock.service">
</context:component-scan>
Java 설정의 경우
- root-context.xml을 대신하는 RootConfig 클래스를 이용해 @ComponentScan을 추가한다.
< RootConfig 클래스 >
@Configuration
@ComponentScan(basePackages="org.zerock.service")
@MapperScan(basePackages= {"org.zerock.mapper"})
public class RootConfig {
... 생략 ....