Contents
1. 초난ê°� DAO ¶
- 사용ìž� ì •ë³´ë¥¼ JDBC API를 ì�´ìš©í•´ DBì—� ì €ìž¥í•˜ê³ ì¡°íšŒí• ìˆ˜ 있는 간단한 DAO 만들기.
- DAO(Data Access Object)
- DB를 사용하여 ë�°ì�´í„°ë¥¼ 조회, 조작하는 기능ì�„ ì „ë‹´í•˜ë�„ë¡� ë§Œë“ ì˜¤ë¸Œì �트.
- DB를 사용하여 ë�°ì�´í„°ë¥¼ 조회, 조작하는 기능ì�„ ì „ë‹´í•˜ë�„ë¡� ë§Œë“ ì˜¤ë¸Œì �트.
1.1. User ¶
- 사용ìž� ì •ë³´ë¥¼ ì €ìž¥í• ë•Œ ìž�바빈 규약ì�„ 따르는 오브ì �트를 ì�´ìš©í•˜ë©´ 편리하다.
- �바빈(JavaBean)
- 간단히 빈ì�´ë�¼ê³ ë�„ 한다.
- �래 �미는 비주얼 툴�서 조작 가능한 컴�넌트.
- 요즘�
- 파ë�¼ë¯¸í„°ê°€ 없는 ë””í�´íЏ ìƒ�성ìž�를 ê°€ì§€ê³ ìžˆê³
- getter와 setter를 통해 조회, ìˆ˜ì •í• ìˆ˜ 있는 프로í�¼í‹°ë¥¼ 가진 오브ì �트를 ì�˜ë¯¸í•œë‹¤.
- 파ë�¼ë¯¸í„°ê°€ 없는 ë””í�´íЏ ìƒ�성ìž�를 ê°€ì§€ê³ ìžˆê³
- 간단히 빈ì�´ë�¼ê³ ë�„ 한다.
- �바빈(JavaBean)
- User : 사용ìž� ì •ë³´ ì €ìž¥ìš© ìž�바빈 í�´ëž˜ìФ
package springbook.user.domain;
public class User {
String id;
String name;
String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- USER 테�블
| 필드명 | 타입 | ì„¤ì • |
| UserId | VARCHAR(10) | Primary Key |
| Name | VARCHAR(20) | Not Null |
| Password | VARCHAR(20) | Not Null |
1.2. UserDao ¶
- UserDao : JDBC를 �용한 등�, 조회 기능� 있는 DAO �래스
package springbook.user.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import springbook.user.domain.User;
public class UserDao {
public void add(User user) throws SQLException, ClassNotFoundException{
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost/springbook", "spring", "book");
PreparedStatement ps = c.prepareStatement("insert into users(id, name, password) values(?,?,?)");
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeUpdate();
ps.close();
c.close();
}
public User get(String id) throws ClassNotFoundException, SQLException{
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost/springbook", "spring", "book");
PreparedStatement ps = c.prepareStatement("select * from users where id = ?");
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.setId(rs.getString("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
rs.close();
ps.close();
c.close();
return user;
}
}
1.3. main()ì�„ ì�´ìš©í•œ 테스트 ¶
- 앞서 ë§Œë“ í�´ëž˜ìŠ¤ê°€ ì œëŒ€ë¡œ ë�™ìž‘하는지 확ì�¸í•˜ë ¤ë©´
- DAOì�˜ 기능ì�„ 사용하는 웹 어플리케ì�´ì…˜ì�„ 만들어 서버ì—� 배치한 ë’¤ 웹 브ë�¼ìš°ì €ë¥¼ 통해 사용해보거나
- UserDao 코드가 �작하는지 확�하기 위해 너무 복잡한 작업� 필요.
- UserDao 코드가 �작하는지 확�하기 위해 너무 복잡한 작업� 필요.
- 오브ì �트가 스스로 ìž�ì‹ ì�„ ê²€ì¦�하ë�„ë¡� 만들어준다.
- DAOì�˜ 기능ì�„ 사용하는 웹 어플리케ì�´ì…˜ì�„ 만들어 서버ì—� 배치한 ë’¤ 웹 브ë�¼ìš°ì €ë¥¼ 통해 사용해보거나
- main 메소드를 �용한 테스트 코드
public static void main(String[] args) throws SQLException, ClassNotFoundException {
UserDao dao = new UserDao();
User user = new User();
user.setId("zeropage");
user.setName("ì œë¡œíŽ˜ì�´ì§€");
user.setPassword("zp");
dao.add(user);
System.out.println(user.getId() + "등� 성공");
User user2 = dao.get(user.getId());
System.out.println(user2.getName());
System.out.println(user2.getPassword());
System.out.println(user2.getId() + "조회 성공");
}
- 테스트가 성공하면 다ì�Œê³¼ ê°™ì�´ ì¶œë ¥ë�œë‹¤.
zeropage 등ë¡� 성공 ì œë¡œíŽ˜ì�´ì§€ zp zeropage 조회 성공
2.1. 관심사ì�˜ 분리 ¶
- 어플리케ì�´ì…˜ì�´ í��기처분ë� 때까지 오브ì �트 설계와 코드는 ë�Šìž„ì—†ì�´ 변한다. ê·¸ë ‡ë‹¤ë©´ 변화ì—� 어떻게 ëŒ€ë¹„í• ê²ƒì�¸ê°€?
- 가장 좋ì�€ 대책 : 변화ì�˜ í�ì�„ 최소한으로 줄ì�¸ë‹¤.
- ë�™ì�¼í•œ 기능 변경ì�„ ìš”ì²í–ˆì�„때
- 단 몇 줄ì�˜ 코드만 ìˆ˜ì •í•˜ê³ ìˆ˜ì •í•œ ë’¤ì—�ë�„ ë¬¸ì œ ì—†ì�´ ìž‘ë�™í•¨ì�„ 보여주는ë�° 5ë¶„ì�´ 걸리는 개발ìž� > 코드를 ìˆ˜ì •í•˜ëŠ”ë�° 5시간ì�´ ê±¸ë¦¬ê³ ìˆ˜ì •í•œ ë’¤ ë¬¸ì œ ì—†ì�´ ìž‘ë�™í•˜ëŠ”ì§€ í™•ì‹ í• ìˆ˜ 없는 개발ìž�
- 단 몇 줄ì�˜ 코드만 ìˆ˜ì •í•˜ê³ ìˆ˜ì •í•œ ë’¤ì—�ë�„ ë¬¸ì œ ì—†ì�´ ìž‘ë�™í•¨ì�„ 보여주는ë�° 5ë¶„ì�´ 걸리는 개발ìž� > 코드를 ìˆ˜ì •í•˜ëŠ”ë�° 5시간ì�´ ê±¸ë¦¬ê³ ìˆ˜ì •í•œ ë’¤ ë¬¸ì œ ì—†ì�´ ìž‘ë�™í•˜ëŠ”ì§€ í™•ì‹ í• ìˆ˜ 없는 개발ìž�
- 어떻게?
- 분리와 확장ì�„ ê³ ë ¤í•œ 설계
- 분리와 확장ì�„ ê³ ë ¤í•œ 설계
- ë�™ì�¼í•œ 기능 변경ì�„ ìš”ì²í–ˆì�„때
- ëª¨ë“ ë³€ê²½ê³¼ ë°œì „ì�€ 한 번ì—� 한 가지 관심사í•ì—� 집중해서 ì�¼ì–´ë‚˜ì§€ë§Œ ê·¸ì—� 따른 작업ì�€ 한 ê³³ì—� 집중ë�˜ì§€ 않는 경우가 많다.
- 관심사� 분리
- 한 가지 관심� 한 군�� 집중�게 하�.
- 관심ì�´ ê°™ì�€ 것ë�¼ë¦¬ëŠ” 하나ì�˜ ê°�ì²´ 안으로, 관심ì�´ 다른 것ì�€ 가능한 ë–¨ì–´ì ¸ ì˜�í–¥ì�„ 주지 않ë�„ë¡� 분리.
- 한 가지 관심� 한 군�� 집중�게 하�.
- 관심사� 분리
2.2.1. UserDaoì�˜ ê´€ì‹¬ì‚¬í• ¶
- DB ì—°ê²°ì�„ 위한 커넥션ì�„ 어떻게 ê°€ì ¸ì˜¬ 것ì�¸ê°€.
- 사용ìž� 등ë¡�/조회를 위한 SQL문ì�„ ë‹´ì�„ Statement를 ë§Œë“¤ê³ ì‹¤í–‰í•˜ëŠ” 것.
- 작업ì�´ ë��ë‚˜ê³ ë¦¬ì†ŒìŠ¤ë¥¼ close하는 것.
- 가장 í�° ë¬¸ì œ : DB ì—°ê²°ì�„ 위한 커넥션 오브ì �트 ê°€ì ¸ì˜¤ê¸°
- add() 메소드와 get() 메소드� ��한 코드가 중복�어 있다.
- 앞으로 수백개ì�˜ DAO 메소드를 ë§Œë“ ë‹¤ê³ í•˜ë©´
- DB 커넥션ì�„ ê°€ì ¸ì˜¤ëŠ” 코드가 수백군ë�°ì—� 중복으로 존재하게 ë�˜ì–´
- DB 커넥션ì�„ ê°€ì ¸ì˜¤ëŠ” ë°©ì‹�ì�´ 바뀌면 수백군ë�°ë¥¼ 하나하나 ìˆ˜ì •í•´ì•¼í•œë‹¤.
- DB 커넥션ì�„ ê°€ì ¸ì˜¤ëŠ” 코드가 수백군ë�°ì—� 중복으로 존재하게 ë�˜ì–´
- 앞으로 수백개ì�˜ DAO 메소드를 ë§Œë“ ë‹¤ê³ í•˜ë©´
- add() 메소드와 get() 메소드� ��한 코드가 중복�어 있다.
2.2.2. 중복 코드ì�˜ 메소드 추출 ¶
- 커넥션ì�„ ê°€ì ¸ì˜¤ëŠ” 중복ë�œ 코드를 분리한다.
- UserDao : getConnection() 메소드를 추출하여 중복ì�„ ì œê±°
public void add(User user) throws SQLException, ClassNotFoundException {
Connection c = getConnection();
…
}
public void get(String id) throws SQLException, ClassNotFoundException {
Connection c = getConnection();
…
}
private Connection getConnection() throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost/springbook", "spring", "book");
}
- ì�´ì œ 수백개ì�˜ DAO 메소드가 있어ë�„ DB 커넥션ì�„ ê°€ì ¸ì˜¤ëŠ” ë°©ì‹�ì�´ 바뀌면 getConnection() 메소드만 ìˆ˜ì •í•´ì£¼ë©´ ë�œë‹¤.
2.2.3. 변경사í•ì—� 대한 ê²€ì¦� : ë¦¬íŒ©í† ë§�ê³¼ 테스트 ¶
- ë¦¬íŒ©í† ë§�
- 코드 내부 구조를 변경하여 재구성하는 작업
- 외부 �작 방�� 변화하지 않�.
- 장ì �
- ë‚´ë¶€ 설계가 ê°œì„ ë�˜ì–´ 코드를 ì�´í•´í•˜ê¸° íŽ¸í•´ì§€ê³ ë³€í™”ì—� 효율ì �으로 대ì�‘í• ìˆ˜ 있다.
- ë‚´ë¶€ 설계가 ê°œì„ ë�˜ì–´ 코드를 ì�´í•´í•˜ê¸° íŽ¸í•´ì§€ê³ ë³€í™”ì—� 효율ì �으로 대ì�‘í• ìˆ˜ 있다.
- ë¦¬íŒ©í† ë§�(마틴 파울러, 켄트 벡 ê³µì €)
- 코드 내부 구조를 변경하여 재구성하는 작업
| DeleteMe) 추후 ë‚´ìš© ë³´ê°• ì˜ˆì • - 김수경 |
3. DAOì�˜ 확장 ¶
- 관심사ì—� ë”°ë�¼ 오브ì �트 나누기
- 관심사가 다르다
- 변화� 성격� 다르다
- 변화ì�˜ 성격ì�´ 다르다는 것ì�€ 변화ì�˜ ì�´ìœ 와 시기, 주기가 다르다는 것ì�„ ì�˜ë¯¸í•¨
- 변화ì�˜ 성격ì�´ 다르다는 것ì�€ 변화ì�˜ ì�´ìœ 와 시기, 주기가 다르다는 것ì�„ ì�˜ë¯¸í•¨
- ì¶”ìƒ�í�´ëž˜ìŠ¤ë¥¼ ë§Œë“¤ì–´ë†“ê³ ìƒ�ì†�ì�„ 통해 변화를 구현하는 방법 -> 불편하다
- 관심사가 다르다
- 1.3.1 �래스� 분리
- 서로 다른 관심사를 ë�…립ì �ì�¸ í�´ëž˜ìŠ¤ë¡œ 분리해보ìž�
- 기존ì�˜ 코드를 ìˆ˜ì •í• ë•ŒëŠ” 기능ì�˜ 변화가 아닌 ë‚´ë¶€ 설계를 변경해 ë�” 나ì�€ 코드를 만드는 것 ì�´ë‹¤(ë¦¬íŒ©í† ë§�)
- ë¦¬íŒ©í† ë§� 후 기능ì�˜ 변화가 없는지 ê²€ì¦�해야 한다. 테스트 코드가 ì�´ë¥¼ ê²€ì¦�í•´ 준다.
- 기존ì�˜ 코드를 ìˆ˜ì •í• ë•ŒëŠ” 기능ì�˜ 변화가 아닌 ë‚´ë¶€ 설계를 변경해 ë�” 나ì�€ 코드를 만드는 것 ì�´ë‹¤(ë¦¬íŒ©í† ë§�)
- 분리� � �래스는 �존관계를 가진다.
- 서로 다른 관심사를 ë�…립ì �ì�¸ í�´ëž˜ìŠ¤ë¡œ 분리해보ìž�
- 1.3.2 �터페�스� �입
- í�´ëž˜ìФ 분리ì—�서 가장 중요한 ì �ì�€ ë‘� í�´ëž˜ìŠ¤ê°€ ë‚®ì�€ ê²°í•©ë�„를 ê°€ì ¸ì•¼ 한다는 것ì�´ë‹¤.
- 추�화
- ì–´ë–¤ 것들ì�˜ 공통ì �ì�¸ 성격ì�„ 뽑아내어 ì�´ë¥¼ 따로 분리해내는 작업
- interface �용
- ìƒ�ì†�보다 ìœ ì—°í•œ 관계 ì„¤ì • 가능
- ì–´ë–¤ 것들ì�˜ 공통ì �ì�¸ 성격ì�„ 뽑아내어 ì�´ë¥¼ 따로 분리해내는 작업
- í�´ëž˜ìФ 분리ì—�서 가장 중요한 ì �ì�€ ë‘� í�´ëž˜ìŠ¤ê°€ ë‚®ì�€ ê²°í•©ë�„를 ê°€ì ¸ì•¼ 한다는 것ì�´ë‹¤.
- 1.3.3 ê´€ê³„ì„¤ì • ì±…ìž„ì�˜ 분리
- 코드ì�˜ í�¬ê¸°ê°€ ìž‘ê³ ê°„ë‹¨í•´ë�„ í�´ëž˜ìŠ¤ì™€ëŠ” 다른 ë�…립ì �ì�¸ 관심사를 ê°€ì§€ê³ ìžˆë‹¤ë©´ 분리해야한다.
- í�´ëž˜ìФì�˜ 확장성ì�„ í•´ì¹ ìˆ˜ 있다.
- í�´ëž˜ìФì�˜ 확장성ì�„ í•´ì¹ ìˆ˜ 있다.
- í�´ëž˜ìŠ¤ê°„ì�˜ ê´€ê³„ì„¤ì •
- 오브ì �트와 오브ì �트간ì�˜ ê´€ê³„ì„¤ì •ì�„ ì�˜ë¯¸í•œë‹¤.
- 런타임 사용관계 : 오브ì �트 사ì�´ì�˜ 관계란 런타임시ì—� 한 오브ì �트가 다른 오브ì �트ì�˜ ë ˆí�¼ëŸ°ìŠ¤ë¥¼ ê°€ì§€ê³ ìžˆëŠ” 것.
- 방법
- ì‚¬ìš©í• ì˜¤ë¸Œì �트를 ë‚´ë¶€ì—�서 ìƒ�성
- ì�¸í„°íŽ˜ì�´ìŠ¤ë¡œ 구현ë�œ 파ë�¼ë©”터를 ì�´ìš©í•´ 외부ì—�서 ì „ë‹¬ë°›ëŠ”ë‹¤. (다형성)
- ì‚¬ìš©í• ì˜¤ë¸Œì �트를 ë‚´ë¶€ì—�서 ìƒ�성
- 오브ì �트와 오브ì �트간ì�˜ ê´€ê³„ì„¤ì •ì�„ ì�˜ë¯¸í•œë‹¤.
- 코드ì�˜ í�¬ê¸°ê°€ ìž‘ê³ ê°„ë‹¨í•´ë�„ í�´ëž˜ìŠ¤ì™€ëŠ” 다른 ë�…립ì �ì�¸ 관심사를 ê°€ì§€ê³ ìžˆë‹¤ë©´ 분리해야한다.
- 1.3.4 윈칙과 패턴
- 개방 �쇄 �칙(OCP) �체지향 설계�칙(SOLID)
- í�´ëž˜ìŠ¤ë‚˜ 모듈ì�€ 확장ì—�는 ì—´ë ¤ 있어야 í•˜ê³ ë³€ê²½ì—�는 닫혀 있어야 한다
- í�´ëž˜ìŠ¤ë‚˜ 모듈ì�€ 확장ì—�는 ì—´ë ¤ 있어야 í•˜ê³ ë³€ê²½ì—�는 닫혀 있어야 한다
- 높� �집�와 낮� 결합�
- 개방 �쇄 �칙� �리
- 높� �집�
- 변화가 ì�¼ì–´ë‚ 때 해당 모듈ì—�서 변하는 부분ì�´ í�¬ë‹¤ëŠ” 것ì�„ ì�˜ë¯¸í•œë‹¤.
- 변화가 ì�¼ì–´ë‚ 때 해당 모듈ì—�서 변하는 부분ì�´ í�¬ë‹¤ëŠ” 것ì�„ ì�˜ë¯¸í•œë‹¤.
- 낮� 결합�
- 높ì�€ ì�‘ì§‘ë�„보다 민ê°�한 사í•
- ê²°í•©ë�„란 하나ì�˜ 오브ì �트가 ì�˜ì¡´ê´€ê³„ì—� 있는 다른 오브ì �트ì—�게 변화를 요구하는 ì •ë�„를 ì�˜ë¯¸í•œë‹¤.
- 변화가 다른 모듈ì�´ë‚˜ 오브ì �트ì—�게 ì „íŒŒë�˜ì§€ 않는 것ì�´ 좋다.
- 높ì�€ ì�‘ì§‘ë�„보다 민ê°�한 사í•
- 개방 �쇄 �칙� �리
- ì „ëžµ 패턴
- 디�� 패턴� �부
- 변경ì�´ 필요한 ì•Œê³ ë¦¬ì¦˜ì�„ ì�¸í…ŒíŽ˜ì�´ìŠ¤ë¥¼ 통해 외부로 ë¶„ë¦¬ì‹œí‚¤ê³ , ì�´ë¥¼ 구체화한 í�´ëž˜ìŠ¤ë¥¼ í•„ìš”ì—� ë”°ë�¼ 바꿔 사용하게 하는 패턴
- 디�� 패턴� �부
- 개방 �쇄 �칙(OCP) �체지향 설계�칙(SOLID)
- ê²°êµ.. 스프ë§�ì�´ëž€?
- ê°�체지향ì � 설계 ì›�칙과 ë””ìž�ì�¸ 패턴ì—� 나타난 장ì �ì�„ ìž�연스럽게 개발ìž�들ì�´ í™œìš©í• ìˆ˜ 있게 해주는 í”„ë ˆìž„ì›Œí�¬
- ê°�체지향ì � 설계 ì›�칙과 ë””ìž�ì�¸ 패턴ì—� 나타난 장ì �ì�„ ìž�연스럽게 개발ìž�들ì�´ í™œìš©í• ìˆ˜ 있게 해주는 í”„ë ˆìž„ì›Œí�¬
4. ì œì–´ì�˜ ì—ì „(IoC) ¶
- 1.4.1 오브ì �트 íŒ©í† ë¦¬
- íŒ©í† ë¦¬
- ê°�ì²´ì�˜ ìƒ�성 방법ì�„ ê²°ì •í•˜ê³ ë§Œë“¤ì–´ì§„ 오브ì �트를 ë�Œë ¤ì¤€ë‹¤.
- 관심사ì�˜ 분리 - 오브ì �트를 ìƒ�성하는 쪽과 ìƒ�성ë�œ 오브ì �트를 사용하는 쪽ì�„ 분리하는 ì—í• ì�„ 한다.
- DaoFactory 장ì � : ì• í”Œë¦¬ì¼€ì�´ì…˜ì�˜ ì»´í�¬ë„ŒíЏ ì—í• ì�„ 하는 오브ì �트와 구조를 ê²°ì •í•˜ëŠ” 오브ì �트를 분리.
- ê°�ì²´ì�˜ ìƒ�성 방법ì�„ ê²°ì •í•˜ê³ ë§Œë“¤ì–´ì§„ 오브ì �트를 ë�Œë ¤ì¤€ë‹¤.
- íŒ©í† ë¦¬
- 1.4.2 오브ì �트 íŒ©í† ë¦¬ì�˜ 활용
- 오브ì �트 ìƒ�성 코드 반복ì�„ 분리한다
- 오브ì �트 ìƒ�성 코드 반복ì�„ 분리한다
public class DaoFactory{
// ConnectionMaker를 ì„¤ì •í•˜ê³ ìƒ�성하는 코드가 반복ë�¨
public UserDao userDao( ){
return new UserDao(new DConnectionMaker());
}
public AccountDao accountDao( ){
return new AccountDao(new DConnectionMaker());
}
public MessageDao messageDao( ){
return new MessageDao(new DConnectionMaker());
}
}
분리 ì „
public class DaoFactory{
public UserDao userDao( ){
return new UserDao(connectionMaker());
}
public AccountDao accountDao( ){
return new AccountDao(connectionMaker());
}
public MessageDao messageDao( ){
return new MessageDao(connectionMaker());
}
// 중복 코드 분리
public ConnectionMaker connectionMaker(){
return new DConnectionMaker();
}
}
분리 후- 1.4.3 ì œì–´ê¶Œì�˜ ì�´ì „ì�„ 통한 ì œì–´ê´€ê³„ ì—ì „
- ì œì–´ì�˜ ì—ì „ì�´ëž€?
- 프로그램ì�˜ ì œì–´ í��름 구조가 뒤바뀌는 것
- ì œì–´ 권한ì�„ 다른 대ìƒ�ì—�게 위임한다.
- í”„ë ˆìž„ì›Œí�¬ëŠ” ì œì–´ì�˜ ì—ì „ì�´ ì �ìš©ë�œ 대표ì �ì�¸ ê¸°ìˆ ì�´ë‹¤.
- ë�¼ì�´ë¸ŒëŸ¬ë¦¬ëŠ” ì• í”Œë¦¬ì¼€ì�´ì…˜ì�´ 능ë�™ì �으로 사용한다.
- 반면 í”„ë ˆìž„ì›Œí�¬ëŠ” ì• í”Œë¦¬ì¼€ì�´ì…˜ 코드가 í”„ë ˆìž„ì›Œí�¬ì—� 사용ë�œë‹¤.
- ë�¼ì�´ë¸ŒëŸ¬ë¦¬ëŠ” ì• í”Œë¦¬ì¼€ì�´ì…˜ì�´ 능ë�™ì �으로 사용한다.
- 프로그램ì�˜ ì œì–´ í��름 구조가 뒤바뀌는 것
- ì œì–´ì�˜ ì—ì „ì�´ëž€?
- 스프ë§�ì�€ IoC를 극한까지 ì �용한 í”„ë ˆìž„ì›Œí�¬ë‹¤.
- í”„ë ˆìž„ì›Œí�¬ëŠ” 분명한 ì œì–´ì�˜ ì—ì „ ê°œë…�ì�´ ì �ìš©ë�˜ì–´ 있어야 한다.
- í”„ë ˆìž„ì›Œí�¬ëŠ” 분명한 ì œì–´ì�˜ ì—ì „ ê°œë…�ì�´ ì �ìš©ë�˜ì–´ 있어야 한다.
5. 스프ë§�ì�˜ IoC ¶
5.1 오브ì �트 íŒ©í† ë¦¬ë¥¼ ì�´ìš©í•œ 스프ë§� IoC
- 5.1.1
- 빈(bean) : 스프ë§�ì�´ ì œì–´ê¶Œì�„ ê°€ì§€ê³ ì§�ì ‘ ë§Œë“¤ê³ ê´€ê³„ë¥¼ 부여하는 오브ì �트. ìž�바빈ì—�서 ë§�하는 빈과 비슷한 오브ì �트 단위ì�˜ ì• í”Œë¦¬ì¼€ì�´ì…˜ ì»´í�¬ë„ŒíЏ. 스프ë§�ì�´ ì§�ì ‘ ìƒ�성과 ì œì–´ë¥¼ 담당하는 오브ì �트만ì�„ 빈ì�´ë�¼ê³ 부른다.
- 빈 íŒ©í† ë¦¬(bean factory) : 빈ì�˜ ìƒ�성과 ê´€ê³„ì„¤ì • 등ì�˜ ì œì–´ë¥¼ 담당하는 IoC오브ì �트. 스프ë§�ì�˜ IoC를 담당하는 핵심 컨테ì�´ë„ˆ. ì�¼ë°˜ì �으로 ì§�ì ‘ 사용하지 ì•Šê³ ì�´ë¥¼ 확장한 ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트를 사용한다.
- ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트(application context) : IoCë°©ì‹�ì�„ ë”°ë�¼ 만들어진 ì�¼ì¢…ì�˜ ë¹ˆíŒ©í† ë¦¬. 별ë�„ì�˜ ì •ë³´ë¥¼ ì°¸ê³ í•´ì„œ 빈ì�˜ ìƒ�성, ê´€ê³„ì„¤ì • 등ì�˜ ì œì–´ 작업ì�„ ì´�괄한다. ì„¤ì • ì •ë³´ë¥¼ 따로 받아와서 ì�´ë¥¼ 활용하는 IoC엔진ì�´ë�¼ê³ ë³¼ 수 있다. 주로 ì„¤ì •ì—�는 xmlì�„ 사용한다.
- ì„¤ì •ì •ë³´ : ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트나 빈 íŒ©í† ë¦¬ê°€ IoC를 ì �용하기 위해 사용하는 ì •ë³´. 주로 IoC 컨테ì�´ë„ˆì—� ì�˜í•´ 관리ë�˜ëŠ” ì• í”Œë¦¬ì¼€ì�´ì…˜ 오브ì �트를 ìƒ�ì„±í•˜ê³ êµ¬ì„±í• ë•Œ 사용ë�œë‹¤.
- 컨테ì�´ë„ˆ/IoC컨테ì�´ë„ˆ : IoCë°©ì‹�으로 빈ì�„ 관리한다는 ì�˜ë¯¸ì—�서 ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트나 빈 íŒ©í† ë¦¬ë¥¼ 컨테ì�´ë„ˆ/IoC컨테ì�´ë„ˆë�¼ê³ ë�„ 한다.
- 빈(bean) : 스프ë§�ì�´ ì œì–´ê¶Œì�„ ê°€ì§€ê³ ì§�ì ‘ ë§Œë“¤ê³ ê´€ê³„ë¥¼ 부여하는 오브ì �트. ìž�바빈ì—�서 ë§�하는 빈과 비슷한 오브ì �트 단위ì�˜ ì• í”Œë¦¬ì¼€ì�´ì…˜ ì»´í�¬ë„ŒíЏ. 스프ë§�ì�´ ì§�ì ‘ ìƒ�성과 ì œì–´ë¥¼ 담당하는 오브ì �트만ì�„ 빈ì�´ë�¼ê³ 부른다.
- 5.1.2
- 빈 íŒ©í† ë¦¬ ë˜�는 ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트ì�˜ ì„¤ì •ì •ë³´ë¥¼ 만드는 방법 ->
- 1. 스프ë§�ì�´ 빈 íŒ©í† ë¦¬ë¥¼ 위한 오브ì �트 ì„¤ì •ì�„ 담당하는 í�´ëž˜ìФë�¼ê³ ì�¸ì‹�í• ìˆ˜ 있ë�„ë¡� @Configurationì�´ë�¼ëŠ” ì• ë…¸í…Œì�´ì…˜ì�„ 추가한다.
- 1. 스프ë§�ì�´ 빈 íŒ©í† ë¦¬ë¥¼ 위한 오브ì �트 ì„¤ì •ì�„ 담당하는 í�´ëž˜ìФë�¼ê³ ì�¸ì‹�í• ìˆ˜ 있ë�„ë¡� @Configurationì�´ë�¼ëŠ” ì• ë…¸í…Œì�´ì…˜ì�„ 추가한다.
- 빈 íŒ©í† ë¦¬ ë˜�는 ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트ì�˜ ì„¤ì •ì •ë³´ë¥¼ 만드는 방법 ->
@Configuration
public class DaoFactory{}
- 2. 오브ì �트를 만들어주는 메소드ì—�는 @Beanì�´ë�¼ëŠ” ì• ë…¸í…Œì�´ì…˜ì�„ 붙여준다.
@Configuration
public class DaoFactory{
@Bean
public UserDao userDao(){ ...}
}
- 만들어진 ì„¤ì •ì •ë³´ë¥¼ 사용하는 ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트ì�˜ ìƒ�성 ë°� 빈 ìƒ�성 ->
public static void main(Strings[] args) throws ClassNotFoundException, SQLException{
ApplicatioContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
}
- 2. 준비ë�œ ApplicationContextì�˜ getBean()메소드를 ì�´ìš©í•´ 등ë¡�ë�œ 빈ì�˜ 오브ì �트를 ê°€ì ¸ì˜¬ 수 있다.
public static void main(Strings[] args) throws ClassNotFoundException, SQLException{
ApplicatioContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao dao = context.getBean("userDao", UserDao.class);
}
getBean()메소드 : ApplicationContextê°€ 관리하는 오브ì �트를 ìš”ì²í•˜ëŠ” 메소드. ""안ì—� 들어가는 것ì�€ ApplicationContextì—� 등ë¡�ë�œ 빈ì�˜ ì�´ë¦„. 빈ì�„ ê°€ì ¸ì˜¨ë‹¤ëŠ” 것ì�€ 메소드를 호출해서 결과를 ê°€ì ¸ì˜¨ë‹¤ê³ ìƒ�ê°�하면 ë�œë‹¤. 위ì—�서는 userDao()ë�¼ëŠ” 메소드ì—� 붙였기 때문ì—� ""안ì—� userDaoê°€ 들어갔다. 메소드ì�˜ ì�´ë¦„ì�´ myUserDao()ë�¼ë©´ "myUserDao"ê°€ ë�œë‹¤. 기본ì �으로 Object타입으로 리턴하게 ë�˜ì–´ìžˆì–´ì„œ 다시 ìº�스팅ì�„ 해줘야 하지만 ìž�ë°” 5 ì�´ìƒ�ì�˜ ì œë„¤ë¦ ë©”ì†Œë“œ ë°©ì‹�ì�„ 사용해 ë‘� 번째 파ë�¼ë¯¸í„°ì—� 리턴 타입ì�„ 주면 ìº�스팅ì�„ 하지 않아ë�„ ë�œë‹¤.
5.2 ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트ì�˜ ë�™ìž‘ë°©ì‹�- 5.2.1
- @Configurationì�´ ë¶™ì�€ í�´ëž˜ìŠ¤ëŠ” ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트가 활용하는 IoC ì„¤ì •ì •ë³´ê°€ ë�œë‹¤. ë‚´ë¶€ì �으로는 ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트가 @Configurationí�´ëž˜ìФì�˜ @Bean메소드를 호출해서 오브ì �트를 ê°€ì ¸ì˜¨ 것ì�„ í�´ë�¼ì�´ì–¸íŠ¸ê°€ getBean() 메소드로 ìš”ì²í• 때 ì „ë‹¬í•´ì¤€ë‹¤.
- @Configurationì�´ ë¶™ì�€ í�´ëž˜ìŠ¤ëŠ” ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트가 활용하는 IoC ì„¤ì •ì •ë³´ê°€ ë�œë‹¤. ë‚´ë¶€ì �으로는 ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트가 @Configurationí�´ëž˜ìФì�˜ @Bean메소드를 호출해서 오브ì �트를 ê°€ì ¸ì˜¨ 것ì�„ í�´ë�¼ì�´ì–¸íŠ¸ê°€ getBean() 메소드로 ìš”ì²í• 때 ì „ë‹¬í•´ì¤€ë‹¤.
- 5.2.2
- ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트를 사용했ì�„ 때 ì–»ì�„ 수 있는 장ì �
- í�´ë�¼ì�´ì–¸íŠ¸ëŠ” 구체ì �ì�¸ íŒ©í† ë¦¬ í�´ëž˜ìŠ¤ë¥¼ 알 필요가 없다.
- ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트는 종합 IoC 서비스를 ì œê³µí•´ì¤€ë‹¤.
- ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트는 빈ì�„ 검색하는 다양한 방법ì�„ ì œê³µí•œë‹¤.
- í�´ë�¼ì�´ì–¸íŠ¸ëŠ” 구체ì �ì�¸ íŒ©í† ë¦¬ í�´ëž˜ìŠ¤ë¥¼ 알 필요가 없다.
- ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트를 사용했ì�„ 때 ì–»ì�„ 수 있는 장ì �
6. 싱글톤 ë ˆì§€ìŠ¤íŠ¸ë¦¬ì™€ 오브ì �트 스코프 ¶
6.1 싱글톤 ë ˆì§€ìŠ¤íŠ¸ë¦¬ë¡œì„œì�˜ ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트
- ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트는 싱글톤ì�„ ì €ìž¥í•˜ê³ ê´€ë¦¬í•˜ëŠ” 싱글톤 ë ˆì§€ìŠ¤íŠ¸ë¦¬ì�´ê¸°ë�„ 하다. 스프ë§�ì�€ 기본ì �으로 별다른 ì„¤ì •ì�´ 없으면 ë‚´ë¶€ì—�서 ìƒ�성하는 빈 오브ì �트를 모ë‘� 싱글톤으로 ë§Œë“ ë‹¤.
- 스프ë§�ì�€ 주로 서버환경ì—� ì �ìš©ë�˜ê¸° 때문ì—� 서버ì—� 걸리는 부하를 줄ì�´ê¸° 위해 빈ì�„ 싱글톤으로 만들게 ë�˜ì–´ìžˆë‹¤. 스프ë§� 컨테ì�´ë„ˆëŠ” 싱글톤ì�„ ìƒ�성, 관리하는 싱글톤 관리 컨테ì�´ë„ˆì�´ê¸°ë�„ 하다.
- ì�¼ë°˜ì �ì�¸ 싱글톤 패턴ì�˜ 구현ì�˜ 한계
- 1. private ìƒ�성ìž�를 ê°€ì§€ê³ ìžˆê¸° 때문ì—� ìƒ�ì†�í• ìˆ˜ 없다.
- 2. 싱글톤� 테스트하기가 힘들다.
- 3. 서버환경�서는 싱글톤� 하나만 만들어지는 것� 보장하지 못한다.
- 4. 싱글톤ì�˜ 사용ì�€ ì „ì—ìƒ�태를 만들 수 있기 때문ì—� 바람ì§�하지 못하다.
- 1. private ìƒ�성ìž�를 ê°€ì§€ê³ ìžˆê¸° 때문ì—� ìƒ�ì†�í• ìˆ˜ 없다.
- 싱글톤 오브ì �트ì�˜ ì�¸ìŠ¤í„´ìŠ¤ 변수를 ìˆ˜ì • 시 서로 ê°’ì�„ ë�®ì–´ì“°ê³ ì�½ì–´ì˜¬ 수 있기 때문ì—� 위험하다. ì�½ê¸°ì „ìš©ì�˜ ì†�성ì�„ 가진 ì •ë³´ë�¼ë©´ ì�¸ìŠ¤í„´ìŠ¤ 변수로 사용해ë�„ 좋다.
- 스코프(scope) : 스프ë§�ì�´ 관리하는 빈ì�´ ìƒ�성ë�˜ê³ ì¡´ìž¬í•˜ê³ ì �ìš©ë�˜ëŠ” 범위. 빈ì�˜ 기본 스코프는 싱글톤으로 컨테ì�´ë„ˆ ë‚´ì—� 한 ê°œì�˜ 오브ì �트만 ë§Œë“¤ì–´ì ¸ì„œ ê°•ì œë¡œ ì œê±°í•˜ì§€ 않는 한 계ì†� ìœ ì§€ë�œë‹¤. 경우ì—� ë”°ë�¼ì„œ 싱글톤 외ì�˜ í”„ë¡œí† íƒ€ìž…(prototype), ìš”ì²(request), 세션(session)스코프 등ì�„ 가질 수 있다.
7. ì�˜ì¡´ê´€ê³„ 주입(DI) ¶
- �존관계 : � �래스 �는 모듈� 있� 때 한 쪽� 변화가 다른 쪽� �향� 미치는 �황.
- ì�˜ì¡´ê´€ê³„ 주입(DI)? : ì�˜ì¡´ê´€ê³„ 주입(Dependency Injection)ì�´ëž€ 스프ë§�ì—� 사용ë�œ ì œì–´ì�˜ ì—ì „(IoC) ë°©ì‹�ì�„ 조금 ë�” 명확하게 나타내기 위해서 사용한 용어ì�´ë‹¤.
- �존관계 주입� 세 가지 조건
- í�´ëž˜ìФ 모ë�¸ì�´ë‚˜ 코드ì—�는 런타임 시ì �ì�˜ ì�˜ì¡´ê´€ê³„ê°€ 드러나지 않는다. 그러기 위해서는 ì�¸í„°íŽ˜ì�´ìФì—�ë§Œ ì�˜ì¡´í•˜ê³ 있어야 한다.
- 런타임 시ì �ì�˜ ì�˜ì¡´ê´€ê³„는 컨테ì�´ë„ˆë‚˜ íŒ©í† ë¦¬ ê°™ì�€ ì œ3ì�˜ 존재가 ê²°ì •í•œë‹¤.
- ì�˜ì¡´ê´€ê³„는 ì‚¬ìš©í• ì˜¤ë¸Œì �트ì—� 대한 ë ˆí�¼ëŸ°ìŠ¤ë¥¼ 외부ì—�서 ì œê³µ(주입)해줌으로ì�¨ 만들어진다.
- í�´ëž˜ìФ 모ë�¸ì�´ë‚˜ 코드ì—�는 런타임 시ì �ì�˜ ì�˜ì¡´ê´€ê³„ê°€ 드러나지 않는다. 그러기 위해서는 ì�¸í„°íŽ˜ì�´ìФì—�ë§Œ ì�˜ì¡´í•˜ê³ 있어야 한다.
- �존관계 주입� 세 가지 조건
- DIì�˜ 장ì � : DI를 받았ì�„ 경우 주입ë�œ 오브ì �트를 ì�¸í„°íŽ˜ì�´ìŠ¤ë¡œ 받는ë�° ì�´ë ‡ê²Œ 하면 코드ì—� 런타임 í�´ëž˜ìŠ¤ì™€ì�˜ 관계가 ì§�ì ‘ 드러나지 않기 때문ì—� 주입시 주입하는 오브ì �트를 바꿔주는 것으로 코드ì�˜ 변경, 확장ì—� 쉽게 대ì�‘í• ìˆ˜ 있다.
- 스프��서� DI
- Bean : 스프ë§�ì—�서는 DI를 쉽게 하기 위해서 Beanì�„ ì�´ìš©í•˜ì—¬ 오브ì �트를 관리한다.
- Bean Factory : 런타임 시ì �ì—�서 ì�˜ì¡´ê´€ê³„를 ê²°ì •í•˜ê¸° 위해 Bean Factoryì—�서 Beanì�„ ê´€ë¦¬í•˜ê³ ì˜¤ë¸Œì �트간ì�˜ 관계를 맺어준다.
- ì�˜ì¡´ê´€ê³„ 검색(Dependency Lookup) : 스프ë§�ì�˜ DIë°©ì‹�ì�„ ì�´ìš©í•˜ê¸° 위해서는 DI를 받는 오브ì �트가 반드시 Beanì�´ì–´ì•¼ 한다. 하지만 DLì�„ ì�´ìš©í•˜ë©´ Beanì�´ 아닌 오브ì �트ì—�서ë�„ ì�˜ì¡´ê´€ê³„를 ì„¤ì •í• ìˆ˜ 있다.
- Bean : 스프ë§�ì—�서는 DI를 쉽게 하기 위해서 Beanì�„ ì�´ìš©í•˜ì—¬ 오브ì �트를 관리한다.
8. XMLì�„ ì�´ìš©í•œ ì„¤ì • ¶
- XML ì„¤ì •
- 스프ë§�ì—�서는 DIì�˜ì¡´ê´€ê³„를 만들 때 ì§�ì ‘ì �으로 코드를 ìˆ˜ì •í•˜ëŠ” 것 외ì—�ë�„ 다양한 ë°©ì‹�ì�„ ì œê³µí•˜ê³ ìžˆë‹¤. XMLì�€ 단순한 í…�스트 파ì�¼ì�´ê¸° 때문ì—� 다루기 ì‰½ê³ ì¶”ê°€ì �ì�¸ 빌드작업ì�´ 필요하지 않다.
- <beans> : @Configuration� 대�한다. 여러 개� <bean>� 들어간다.
- <bean> : @Bean� 붙� �바 메소드� 대�한다.
- <id> : @Bean 메소드� �름. getBean()�서 사용한다.
- <class> : @Bean 메소드가 return하는 값. 패키지까지 모� � 줘야 한다.
- <property> : @Bean 메소드ì—� DI를 í• ë•Œ 사용한다. ìˆ˜ì •ìž� 메소드ì�´ë‹¤.
- <name> : ìˆ˜ì •ìž� 메소드ì—�서 set부분ì�„ ì œì™¸í•œ 나머지 부분ì�˜ ì�´ë¦„ì�´ë‹¤.
- <ref> : ìˆ˜ì •ìž� 메소드를 ì�´ìš©í•´ì„œ ì£¼ìž…í• ì˜¤ë¸Œì �트ì�˜ Beanì�˜ idì�´ë‹¤.
- <value> : 다른 Bean 오브ì �트가 아니ë�¼ 단순 ê°’ì�„ ì£¼ìž…í• ë•Œ <ref> ëŒ€ì‹ ì‚¬ìš©í•œë‹¤. 스프ë§�ì—�서 프로í�¼í‹°ì�˜ ê°’ì�„ ì �ì ˆí•˜ê²Œ 변환하기 때문ì—� 스트ë§�, 오브ì �트 등 다양한 ê°’ì�„ ì‚¬ìš©í• ìˆ˜ 있다.
- <name> : ìˆ˜ì •ìž� 메소드ì—�서 set부분ì�„ ì œì™¸í•œ 나머지 부분ì�˜ ì�´ë¦„ì�´ë‹¤.
- <id> : @Bean 메소드� �름. getBean()�서 사용한다.
- <bean> : @Bean� 붙� �바 메소드� 대�한다.
- <beans> : @Configuration� 대�한다. 여러 개� <bean>� 들어간다.
- 예시 (Java 코드)
@Configuration
class DaoFactory {
...
@Bean
public ConnectionMaker connectionMaker() {
return new DConnectionMaker();
}
@Bean
userDao setConnectionMaker(connectionMaker()) {
... };
}
- 예시 (XML)
<beans> <bean id="myConnectionMaker" class="springbook.user.dao.DConnectionMaker" /> <bean id="userDao" class="springbook.dao.UserDao"> <property name="connectionMaker ref="myConnectionMaker" /> </bean> </beans>
- XMLì�„ ì�´ìš©í•˜ëŠ” ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트
- ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트 ìƒ�성시 GenericXmlApplicationContext("xml 경로")를 ì�´ìš©í•´ì„œ 컨í…�스트를 ìƒ�성한다.
- ì• í”Œë¦¬ì¼€ì�´ì…˜ 컨í…�스트 ìƒ�성시 GenericXmlApplicationContext("xml 경로")를 ì�´ìš©í•´ì„œ 컨í…�스트를 ìƒ�성한다.
ApplicationContext context = new GenericXmlApplicationContext("springbook/user/dao/daoContext.xml")










