2023. 10. 15. 15:23ㆍ개발/spring&springboot
이전에 초난감 DAO에 대해서 소개하며
인터페이스를 UserDAOTest의 main클래스에서 UserDAO에 interface 객체를 주입하는 식으로 마무리를 지었다.
하지만 이 부분은 얼렁뚱땅 넘어간 부분이다.
UserDAOTest는 test를 맡는 부분인데 UserDAO가 맡고 있던 DB 생성을 어떤 것으로 할지 구현 클래스 결정하는 역할도 겸임하고 있다.
성격이 다르므로 이것도 분리해야한다.
이렇게 분리될 기능은 UserDAO와 ConenctionMaker 구현 클래스 오브젝트를 만드는 것과, 그렇게 만들어진 두 개의 오브젝트가 연결돼서 사용할 수 있도록 관계를 맺어주는 것이다.
🎈팩토리
분리시킬 기능을 담당하는 클래스를 하나 만들어보자.
객체의 생성방법을 결정하고 만들어진 오브젝트를 돌려주는 것인데. 이러한 일을 하는 오브젝트를 Factory, 팩토리 라고 부른다.
디자인패턴에서 말하는 추상 팩토리 패턴, 팩토리 메소드 패턴과는 다르다.
단지 오브젝트를 생성하는 쪽과, 생성된 오브젝트를 사용하는 쪽의 역할과 책임을 깔끔하게 분리하려는 목적으로 사용하는 것일 뿐이다.
팩토리 역할을 맡을 클래스를 DAOFactory라고 해보자.
그리고 UserDAOTest에 담겨있던 UserDAO, ConnectionMaker 관련 생성 작업을 DAOFactory로 옮긴다.
Public clas DAOFactory{
public UserDAO userDAO(String[] args) throws ClassNotFoundException, SQLException {
ConnectionMaker connectionMaker = new DConnectionMaker();
UserDAO userDao = new UserDAO(conenctionMaker);
return userDao;
}
}
위와 같이 만들어서 객체를 반환해주면
Public clas UserDAOTest{
public static void main(String[] args) throws ClassNotFoundException, SQLException {
UserDAO dao = new DaoFactory().UserDAO();
}
}
UserTest는 구현 클래스를 결정하는 책임을 갖지 않는다.
바로 UserDAO의 add, get 메서드를 쓸 수 있다.
🎈오브젝트 팩토리의 활용
DAOFactory class를 다시 생각해보자.
이 팩토리 메서드는 객체를 생성해서 반환해주는 역할이라면 UserDAO뿐만 아니라 다른 DAO도 들어갈 것이다.
가령, MessageDAO, AccountDAO 같은 것들 말이다.
Public clas DAOFactory{
public UserDAO userDAO() {
return new UserDAO(new DConnectionMaker());
}
}
public MessageDAO userDAO(){
return new MessageDAO(new DConnectionMaker());
}
}
public AccountDAO userDAO() {
return new AccountDAO(new DConnectionMaker());
}
}
여기서 드는 생각.
new DcoonectionMaker()의 중복이다.
모든 클래스는 DB연결을 하므로, new DcoonectionMaker()를 반복하여 써주는 것이다.
즉, ConnectionMAker 구현클래스를 선정하고 생성하는 코드의 중복.
중복 문제를 해결하기 위해 이또한 분리해보자.
Public clas DAOFactory{
public UserDAO userDAO() {
return new UserDAO(connectionMaker());
}
}
public MessageDAO userDAO() {
return new MessageDAO(connectionMaker());
}
}
public AccountDAO userDAO(){
return new AccountDAO(connectionMaker());
}
}
public ConnectionMaker connectionMaker() {
return new DConnectionMaker();
}
}
🎈제어권의 이전을 통한 제어관계 역전(IOC)
우리는 제어의 역전을 이용했다.
제어의 역전이라는 개념이란, 프로그램의 제어 흐름 구조가 뒤바뀌는 것이라고 설명할 수 있다.
대개 우리는 main()에소드에서 프로그램이 시작되는 지점에서 다음에 사용할 오브젝트(객체)를 결정하고, 결정한 오브젝트를 생성하고, 만들어진 오브젝트에 있는 메소드를 호출하고, 그 오브젝트 메소드 안 에서 다음에 사용할 것을 결정하고 호출하는 식의 작업이 반복된다.
이런 프로그램 구조에서 각 오브젝트는 프로그램 흐름을 결정하거나, 사용할오브젝트를 구성하는 작업에 능동적으로 참여한다.
지금껏 했던 UserDAO의 초기 코드를 보아도, test용 main()메소드는 UserDAO 클래스의 오브젝트를 직업 생성하고, 만들어진 오브젝트의 메소드를 사용했다.
UserDAO도 자신이 사용할 ConnectionMaker의 구현클래스를 자신이 결정하고, 오브젝트를 필요한 시점에 생성하고 각 메소드에서 사용했다.
모든 종류의 작업을 사용하는 쪽에서 제어를 했다는 소리다.
이 제어를 뒤집는 것이 제어의 역전이다.
즉, 오브젝트는 자신이 사용할 오브젝트를 스스로 선택하지 않는다.
모든 제어 권한은 다른 대상에게 위임하기 떄문이다.
main()과 같은 엔트리 포인트를 제외하면 모든 오브젝트는 위임받은 제어 권한을 갖는 특별한 오브젝트에 의해 결정되고 만들어진다.
이러한 제어의 역전 개념은 폭넓에 적용되어 잇다.
서블릿을 생각해보자.
서블릿을 개발자가 개발하여 서버에 배포할 수는 있지만, 그 실행을 개발자가 직접 제어할 수 있는 방법은 없다. 서블릿 안에 main()메소드가 있어 직접 실행시킬 수 있는 것도 아니다.
서블릿 개념
https://coding-factory.tistory.com/742
[Web] 서블릿(Servlet)이란 무엇인가? 서블릿 총정리
서블릿(Servlet)이란? 서블릿이란 Dynamic Web Page를 만들 때 사용되는 자바 기반의 웹 애플리케이션 프로그래밍 기술입니다. 웹을 만들때는 다양한 요청(Request)과 응답(Response)이 있기 마련이고 이 요
coding-factory.tistory.com
이후 우리는 UserDAO를 수정하여 interface를 생성하고, Factory 메서드를 사용하여 객체를 만들고 반환하면 그것을 UserDAO의 생성자에서 받아 처리하는 식의 코드를 짰었다.
제어권을 상위 템플릿 메소드에 넘기고 자신은 필요할 때 호출되어 기능하는 부분만 구현해 놓으면 이후에 add, get을 쓸 수 있는 것이다.
이것이 제어의 역전을 했다고 볼 수 있는 것이다.
프레임 워크도 제어의 역전 개념이 적용된 대표적인 기술이다.
프레임워크와 라이브러리의 차이는 비슷하지만 다르다.
라이브러리는 사용자가 직접 애플리케이션 흐름을 제어하지만, 프레임워크는 거꾸로 애플리케이션 코드가 프레임워크에 의해 사용된다.
즉, 프레임워크가 흐름을 주도하는 중에 개발자가 만든 애플리케이션 코드를 사용하도록 하는 것이다.
이 위의 과정은 IoC프레임워크라고 불리는 스프링 없이도, IoC 개념을 적용해본 셈이다.
🎈스프링의 IoC(제어의 역전)
이제 스프링을 사용해보자.
그전에 개념을 학습해보자.
1. 애플리케이션 컨텍스트와 설정정보
DaoFactory를 스프링에서 사용이 가능하도록 해보자.
스프링에서는 스프링이 제어권을 가지고, 직접 만들고, 관계를 부여하는 오브젝트를 빈 이라고 부른다.
쉽게 말해서 스프링이 직접 생성과 제어를 담당하는 오브젝트라고 할 수 있다. 이는 당연히 제어의 역전이 되어있다.
그리고 이 빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리라고 하며 이를 좀더 확장한 것이 애플리케이션 컨텍스트를 주로 사용한다.
빈팩토리는 애플리케이션과 동일하다고 보면 되지만, 빈 팩토리라고 말할 때는 빈을 생성하고 관계 설정하는 IoC의 기본 기능에 초점을 맞춘 것이고, 애플리케이션 컨텍스트라고 할 때에는 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진이라는 의미가 좀더 부각된다.
설정정보/설정 메타정보 : 스프링의 설정정보란, 애플리에키션 컨텍스트 또는 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타정보를 말하며 Contigration이라고 한다.
컨테이너, IoC 컨테이너 : IoC방식으로 빈을 관리한다는 의미, 애플리케이션 컨텍스트나 빈 팩토리를 IoC컨테이너라고도 한다.
그냥 컨테이너, 스프링 컨테이너라고 할 때 애플리케이션 컨텍스트를 말한다고 보면 된다.
이를테면, 스프링에 빈을 등록하고 라는 말은 = 스프링 컨테이너, 애플리케이션 컨텍스트에 빈을 등록한다는 말과 상통한다.
🎈싱글톤 레지스트리, 오브젝트 스코프
스프링 빈 같은 것을 사용하지 않았던 우리가 만든 제어의 역전 개념이 들어간 DAOFactory는
DAOFactory 객체를 생성하여 userDAO 메서드를 호출할 때 마다 새로운 객체가 나온다.
DAOFactory factory = new DAOFactory();
UserDAO dao1 = factory .UserDAO();
UserDAO dao2 = factory .UserDAO();
print(dao1);
print(dao2)2;
위의 코드를 실행하면 dao1의 주소1과 2가 다른 주소가 나온다. 그 의미는 각기 다른 장소에 객체가 저장되어 있다는 소리다.
그렇다면 우리가 만든 spring 방식은?
DAOFactory를 사용하는 애플리케이션 컨텍스트
Public clas DAOFactory{
public UserDAO userDAO(){
return new UserDAO(connectionMaker());
}
public ConnectionMaker connectionMaker() {
return new DConnectionMaker();
}
}
이전에 했던 DAOFactory class의 userDAO 메서드, 이걸 스프링식으로 바꿔보자.
@Configuration
Public clas DAOFactory{
@Bean
public UserDAO userDAO(){
return new UserDAO(connectionMaker());
}
@bean
public ConnectionMaker connectionMaker() {
return new DConnectionMaker();
}
}
@Configuration, @Bean이라는 태그 빼고 차이가 없다.
이 위의 태그 같은 것을 애노테이션, 어노테이션이라고 부른다.
이 어노테이션 덕분에 스프링의 빈 팩토리, 컨텍스트 애플리케이션이 사용할 수 있는 오브젝트 설정 담당 클래스라고 인식할 수 있는 것이다.
@Configuration : 해당 클래스가 빈팩토리를 위한 객체 설정 담당 클래스임을 인식할 수 있도록 하는 어노테이션
@Bean : 객체를 만들어주는 메소드에 붙이는 어노테이션
어노테이션 종류들
[Java / Spring ] 어노테이션(@, annotation)의 정의와 종류
(계속 추가중 / 최종수정일:20200831) 어노테이션(@, annotation)이란? Annotation은 Java5부터 새롭게 추가된 문법요소이다. 사전적으로는 "주석"이라는 의미를 가지고 있으며, 자바 코드에 @를 이용해 주석
prinha.tistory.com
이제 이 DAOFactory를 설정정보로 사용하는 애플리케이션 컨텍스트를 만들어보자.
Public clas UserDAOTest{
public static void main(String[] args) throws ClassNotFoundException, SQLException {
UserDAO dao = new DaoFactory().UserDAO();
}
}
이전에 쓰던 UserDAOTest.
Public clas UserDAOTest{
public static void main(String[] args) throws ClassNotFoundException, SQLException {
ApplicationContext context = new AnnotationConfingApplicationContext(DAOFactory.class);
UserDAO dao = context.getBean("userDAO", UserDao.class);
}
}
스프링식으로 바꾼 UserDAOTest.
직접 생성하지 않고 AppliacationCoontext 오브젝트에서 등록된 빈의 이름만을 불러 객체를 생성하는 모습이다.
여기서 getBean 메서드를 이용하여 오브젝트를 가져오는 코드이다.
🎈애플리케이션 컨텍스트 동작방식
클라이언트에서 userDAO를 객체를 요청하면 ApplicationContext에서 빈 목록 중 userDAO 이름의 UserDAO.class가 있는 지 getBean으로 조회하여 생성요청을 하면, DaoFacotory에서 UserDAO를 생성하고 그것을 사용자가 사용한다.
장점
1. 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없음
2. 애플리케이션 컨텍스트는 종합 IoC 서비스를 제공
3. 애플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공
ApplicationContext context = new AnnotationConfingApplicationContext(DAOFactory.class);
UserDAO dao3 = context.getBean("userDAO", UserDao.class);
UserDAO dao4 = context.getBean("userDAO", UserDao.class);
print(dao3);
print(dao4);
실제로 코드상에서 동작하려면 System.out.println()으로 해야하는데 편의상 print로 썼다.
위의 결과는 같은 주소값이 나온다.
getBean에 의해서 UserDAO가 호출해서 객체가 만들어지는 거 아닌가? 그럼 똑같은 주소가 나오면 안 될 것 같은데?
라는 생각이 들 수 있다.
애플리케이션 컨텍스트는 싱글톤 레지스트리이기도 해서 그렇다.
자바가 대규모 엔터프라이징 목적으로 사용이 될 때에는 부하가 걸릴까봐 있었던 방식이라고 한다.
'개발 > spring&springboot' 카테고리의 다른 글
[spring] 1. 토비의 스프링, 초난감 DAO (1) | 2023.10.15 |
---|---|
Springboot+swagger 연동 (0) | 2023.10.05 |
[springboot] 0. 스프링부트 프로젝트를 위한 공부, 시작 소감 (0) | 2023.04.17 |