remagine
토비의 스프링 3.1 읽기 (2) 본문
토비의 스프링 3.1 읽기 2번째 시간
1. 제어의 역전(IOC)
App의 Test를 담당하던 UserDaoTest클래스는 어떤 ConnectionMaker 구현 클래스를 사용할 지를 결정하는 기능이 추가되어 있다. 이것은 테스트 클래스인 UserDaoTest에 다른 책임까지 함께 있는 것이 되어버렸기 때문에 분리하는 것이 필요하다.
1.1 팩토리
팩토리는 객체의 생성방법을 결정하고 만들어진 오브젝트를 돌려주는 클래스를 말한다. 디자인 패턴의 팩토리 패턴과는 다르니 혼동하지 말자. 어떻게 만들지 와 어떻게 사용할지는 분명히 다른 관심사이다.
DaoFactory 클래스 만들기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package springbook.user.dao; public class DaoFactory { /** * 팩토리의 메소드는 UserDao 타입의 오브젝트를 어떻게 만들고, 어떻게 준비시킬지를 결정한다. * @return */ public UserDao userDao(){ ConnectionMaker connectionMaker = new DConnectionMaker(); UserDao userDao = new UserDao(connectionMaker); return userDao; } } | cs |
DaoFactory 의 userDao 메소드를 호출하면 DConnectionMaker를 사용해 DB커넥션을 가져오도록 이미 설정된 UserDao 오브젝트를 돌려준다. UserDaoTest는 이제 UserDao가 어떻게 만들어지는지 어떻게 초기화되어 있는지에 신경 쓰지 않고 팩토리로부터 UserDao 오브젝트를 받아다가, 자신의 관심사인 테스트를 위해 활용하기만 하면 그만이다. 이렇게 해서 각각이 자신의 책임에만 충실하도록 역활에 따라 분리하는 작업을 마쳤다.
1 | UserDao dao = new DaoFactory().userDao(); | cs |
이제 UserDao는 DaoFactory를 통해 초기화된 채로 생성된다
1.2 설계도로서의 팩토리
UserDao와 ConnectionMaker는 각각 애플리케이션의 핵심적인 데이터 로직과 기술 로직을 담당하고 있고, DaoFactory는 이런 애플리케이션의 오브젝트들을 구성하고 그 관계를 정의하는 책임을 맡고 있음을 알 수 있다. 전자가 실질적인 로직을 담당하는 컴포넌트라면, 후자는 애플리케이션을 구성하는 컴포넌트의 구조와 관계를 정의한 설계도 같은 역활을 한다고 볼 수 있다.
팩토리란 어떤 오브젝트가 어떤 오브젝트를 사용하는 지를 정의해놓은 코드라고 보면 된다.
1.3 오브젝트 팩토리 활용
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package springbook.user.dao; public class DaoFactory { /** * 팩토리의 메소드는 UserDao 타입의 오브젝트를 어떻게 만들고, 어떻게 준비시킬지를 결정한다. * @return */ public UserDao userDao(){ ConnectionMaker connectionMaker = new DConnectionMaker(); 중복1 UserDao userDao = new UserDao(connectionMaker); return userDao; } public AccountDao accountDao(){ ConnectionMaker connectionMaker = new DConnectionMaker(); 중복2 UserDao userDao = new UserDao(connectionMaker); return userDao; } public MessageDao messageDao(){ ConnectionMaker connectionMaker = new DConnectionMaker(); 중복3 UserDao userDao = new UserDao(connectionMaker); return userDao; } } | cs |
만일 위와 같이 DaoFactory가 여러 종류의 Dao를 생산해야 한다면 어떻게 될까?
ConnectionMaker의 구현 클래스가 달라질 때 마다 , 변경해줘야 하는 번거로움이 생긴다
중복되는 부분을 별로의 메소드로 분리해내는 리팩토링을 실행해 주자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package springbook.user.dao; public class DaoFactory { /** * 팩토리의 메소드는 UserDao 타입의 오브젝트를 어떻게 만들고, 어떻게 준비시킬지를 결정한다. * @return */ public UserDao userDao(){ return new UserDao(connectionMaker()); } public AccountDao accountDao(){ return new UserDao(connectionMaker()); } public MessageDao messageDao(){ return new UserDao(connectionMaker()); } private ConnectionMaker connectionMaker() { ConnectionMaker connectionMaker = new DConnectionMaker(); return connectionMaker; } } | cs |
이제 connectionMaker의 구현 클래스가 변경이 되도, 소스 하나만 바꾸면 전체 Dao에 적용이 된다.
2. 제어권 이전을 통한 제어관계 역전
제어의 역전 : 프로그램의 제어 흐름 구조가 뒤바뀌는 것을 의미
요약 : 기존의 사용에서는 오브젝트는 자신이 사용할 클래스를 결정하고, 언제 그 오브젝트를 만들지 스스로 관장했다.
제어의 역전이란 이런 제어 흐름의 개념을 거꾸로 뒤집는 것이다. 이제 오브젝트는 자신이 사용할 오브젝트를 스스로 선택하지 않고, 생성하지도 않는다. 모든 제어 권한을 자신이 아닌 다른 대상에게 위임하기 때문이다.
IoC는 지금까지 우리가 했던 UserDao 개선작업의 결과이다. 관심을 분리하고, 책임을 분리하고 유연하게 확장가능 한 구조를 적용하는 작업이었다.
제어의 역전에서는 프레임워크 또는 컨테이너 같이 애플리케이션 컴포넌트의 생성과 관게설정, 사용, 생명주기 관리등을 관장하는 존재가 필요하다. DaoFactory는 오브젝트 수준의 가장 단순한 IoC 프레임워크라 볼 수 있다.
3. 스프링 IoC
빈 팩토리와 애플리케이션 컨텍스트는 스프링의 핵심이다.
3.1 애플리케이션 컨텍스트와 설정정보
스프링에서는 스프링이 직접 제어권을 가지고 만들고 관계를 부여하는 오브젝트를 빈bean이라고 부른다. 오브젝트 단위의 애플리케이션 컴포넌트를 말한다. 동시에 스프링 빈은 스프링 컨테이너가 생성과 관계설정, 사용등을 제어해주는 제어의 역전이 적용된 오브젝트를 가리키는 말이다.
빈 팩토리 : 스프링에서 빈의 생성과 관계설정같은 제어를 담당하는 IoC오브젝트
애플리케이션 컨텍스트 : IoC방식으로 만들어진 일종의 빈 팩토리
빈 팩토리 := 애플리케이션 컨텍스트
3.2 DaoFactory를 설정정보로 변경하기
@Configuration : 빈 팩토리를 위한 오브젝트 설정을 담당하는 클래스 명시
@Bean : 오브젝트를 만들어주는 메소드에 명시
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package springbook.user.dao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class DaoFactory { /** * 팩토리의 메소드는 UserDao 타입의 오브젝트를 어떻게 만들고, 어떻게 준비시킬지를 결정한다. * @return */ @Bean public UserDao userDao(){ return new UserDao(connectionMaker()); } /* public AccountDao accountDao(){ return new UserDao(connectionMaker()); } public MessageDao messageDao(){ return new UserDao(connectionMaker()); }*/ @Bean private ConnectionMaker connectionMaker() { ConnectionMaker connectionMaker = new DConnectionMaker(); return connectionMaker; } } | cs |
애플리케이션 컨텍스트를 적용한 UserDaoTest
1 2 3 4 5 6 7 8 9 10 11 12 13 | import springbook.user.domain.User; public class UserDaoTest { public static void main(String[] args) throws ClassNotFoundException, SQLException { ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class); UserDao dao = context.getBean("userDao",UserDao.class); /*UserDao dao = new DaoFactory().userDao();*/ | cs |
'Spring' 카테고리의 다른 글
토비의 스프링 3.1 읽기 (1) (0) | 2016.09.26 |
---|---|
spring.io에서 spring 따라 만들기 (0) | 2016.09.24 |