Download presentation
Presentation is loading. Please wait.
1
IOC, DI 2015 Web Service Computing
2
UserDao 회원가입을 위해 DB와 연동할 DAO를 만들어보자. UserDao DAO (Data Access Object)
public class UserDao { public void add(User user) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection c = DriverManager.getConnection("jdbc:mysql://localhost/springbook?characterEncoding=UTF-8", “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 { 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(); return user;
3
테스트 코드 테스트 코드 잘 동작하는 위 코드를 수정하고 개선해야 하는 이유? 스파게티 코드 (Spaghetti Code)
public static void main(String[] args) throws ClassNotFoundException, SQLException { UserDao dao = new UserDao(); User user = new User(); user.setId(“admin"); user.setName(“David"); user.setPassword(“1234"); 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() + " 조회 성공"); }
4
관심사의 분리 관심사의 분리 (Separation of Concerns) 개발자에게 요구되는 역량
관심이 같은 사항들은 하나의 객체 또는 주변 객체로 모음 관심이 다른 사항들은 가능한 따로 떨어져서 서로 영향을 주지 않도록 분리 소프트웨어 공학의 모듈화 (Modulization)와 유사 개발자에게 요구되는 역량 미래의 변화를 어떻게 대비하는가? 비지니스 로직의 변화는 집중된 한가지 관심에 대해 일어나지만 그에 따른 코딩 작업은 한 곳에 집중되지 않는 경우가 많다. 그러한 로직의 변화에 대처하여 자유롭고 편리하게 변경, 발전, 확장시킬 수 있는 역량 필요
5
커넥션 만들기의 추출 UserDao에서의 관심사항 예 Refactoring (리팩토링) DB 연결을 위한 커넥션 설정
SQL 쿼리문 생성 및 실행 리소스 반환 Refactoring (리팩토링) 외부의 동작방식에는 변화 없이 내부 구조를 변경해서 코드를 재구성하는 작업 또는 기술 코드 내부 설계가 개선되어 코드를 이해하기가 편해지고 이후 변화에 효율적으로 대응가능 생산성 및 코드 품질이 올라감 DB 연결을 위한 커넥션 설정 리팩토링
6
커넥션 만들기의 추출 중복 코드를 단일 메소드로 추출 (Extract Method)
7
DB커넥션 만들기의 독립 변화에 유연히 대처가 가능한 DAO 상황설명
본인이 만든 UserDao가 유명해져서 N사와 D사에서 구매 주문이 들어옴. N사와 D사가 각기 다른 종류의 DB를 사용하고 있어서 DB 커넥션을 가져오는 방법이 상이함. DB 커넥션을 가져오는 방법은 납품 이후에도 변경될 가능성이 있음. N사와 D사 스스로 원하는 DB 커넥션 생성 방식을 적용해가면서 UserDao를 사용하게 하려고 함.
8
클래스의 분리 두 개의 별다른 관심 사항 N사와 D사에서 DB 연결을 어떻게 만들든 데이터 엑세스 로직에는 변함이 없어야 함
데이터 엑세스 로직을 어떻게 만들 것인가? DB연결을 어떻게 만들 것인가? SQL 쿼리 문 구성 DB에 저장할 정보 DB에서 꺼내올 정보 어떤 드라이버를 사용할 것인가 연결 URL 연결시 사용할 계정 정보
9
클래스의 분리 클래스의 완전 분리 두 개의 독립된 클래스로 분리
10
클래스의 분리 클래스의 완전 분리 두 개의 독립된 클래스로 분리
makeNewConnection() throws ClassNotFoundException, SQLException {
11
클래스의 분리 UserDao 외 다른 Dao까지 구성한다면 어떻게 될까? public class UserDao {
private SimpleConnectionMaker scm; public UserDao() { scm = new SimpleConnectionMaker(); } public class AccountDao { public AccountDao() { public class MessageDao { public MessageDao() { public class FileDao { public FileDao() { public class BookDao { public BookDao() {
12
클래스의 분리 클래스의 완전 분리 두 개의 독립된 클래스로 분리 앞 코드의 문제점 근본적인 문제의 원인
Dao 클래스들이 SimpleConnectionMaker라는 특정 클래스에 종속 DB 커넥션 생성 방법을 변경한 새로운 클래스(N사전용 혹은 D사 전용)를 사용하기 위해서는 Dao의 소스를 모두 함께 변경해야 함. 근본적인 문제의 원인 Dao에서 DB 커넥션을 가져오기 위한 정보 (클래스 이름, 메소드 이름)를 너무 많이 알고 있기 때문임 즉, Dao가 DB 커넥션을 제공하는 클래스에 종속됨 simpleConnectionMaker = new SimpleConnectionMaker(); … Connection c = simpleConnectionMaker.makeNewConnection();
13
관계설정 책임의 분리 주목해야 할 사항 위 관심사를 UserDao에서 분리하는 것이 목표
왜 UserDao에서 ConnectionMaker의 특정 구현 클래스를 정하고, 사용하는 일을 담당해야 하나? 위 관심사를 UserDao에서 분리하는 것이 목표 그렇다면, 관계 설정 관심사를 담당할 클래스는? UserDao를 직접 이용하는 클래스 UserDao는 이러한 관계 설정에 있어서 수동적이어야 함 UserDao는 생성자 또는 setter 메소드로 주는 Connection만 받아서 처리하면 된다. 즉, UserDao는 유저를 add하고 get 하는 일만 담당하면 된다.
14
관계설정 책임의 분리 관심사항의 철저한 분리 UserDao에서 새롭게 구현된 생성자
관계설정 책임이 추가된 UserDAO 클라이언트인 UserDaoTest 클래스와 main() 메소드
15
관계설정 책임의 분리 관계설정 책임을 담당한 UserDaoTest 클래스가 추가된 구조
UserDao 생성자는 ConnectionMaker 인터페이스 타입으로 객체를 전달받기 때문에 ConnectionMaker를 구현한 어떠한 클래스의 객체라도 전달 받을 수 있다. 하지만, UserDao 객체는 전달받은 ConnectionMaker 객체가 어떠한 객체인지 전혀 알지도, 알 필요도 없다.
16
원칙과 패턴 개방 폐쇄 원칙 (OCP, Open-Closed Principle)
클래스나 모듈은 확장에는 열려있어야 하고 변경에는 닫혀있어야 한다. UserDao에 영향을 주지 않고 인터페이스를 사용하여 DB 연결 방법 기능 확장에는 열려있다. 자신의 핵심 기능을 구현한 코드는 그러한 변화에 전혀 영향을 주지 않는다.
17
원칙과 패턴 높은 응집도 (High Coherence) 낮은 결합도 (Low Coupling)
하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되어 있어야 한다. ConnectionMaker는 자체의 응집력을 유지하면서 확장되고 발전할 수 있다. 이러한 발전이 UserDao등의 다른 클래스에 전혀 영향을 주지 않는다. 낮은 결합도 (Low Coupling) 책임과 관심사가 서로 다른 객체 또는 모듈끼리는 느슨하게 연결된 형태 (서로간의 독립성)를 유지해야 한다. 결합도 (Coupling) 하나의 객체에 변경이 일어날 때 관계를 맺고 있는 다른 객체에 변화를 요구하는 정도 UserDao와 ConnectionMaker간의 관계는 매우 느슨하게 연결되어 있다.
18
제어의 역전 (Inversion of Control, IoC)
19
오브젝트 팩토리 (Object Factory)
UserDaoTest에서 “관계설정 기능”의 분리 필요 UserDaoTest는 말그대로 Dao를 테스트하기 위한 객체로 테스트 본연의 기능에만 집중하면 된다. Connection을 만드는 일까지 할 필요가 없음. 팩토리를 사용하는 UserDaoTest 자신의 본래 관심사인 테스트에 집중 가능
20
오브젝트 팩토리의 활용 DaoFactory 구성 예
21
제어권 이전을 통한 제어관계 역전 제어의 역전 (Inversion of Control) 제어의 역전 활용 예
임의의 객체는 자신이 사용할 다른 객체를 선택/생성하지 않는다. 객체 스스로가 향후 어떻게 만들어지고 어디서 사용될지 알 수 없다. 모든 제어 권한은 다른 객체(상위)에게 위임 제어의 역전 활용 예 스프링을 포함한 각종 프레임워크 프레임워크에 올려지는 각종 프로그램들은 프레임워크에서 직접 흐름이 제어된다. 프레임워크라는 이름 자체가 IoC를 사용하고 있다는 뜻
22
제어권 이전을 통한 제어관계 역전 UserDao와 DaoFactory에서의 제어의 역전 IoC의 장점 스프링과 IoC
자신이 활용할 ConnectionMaker도 팩토리에 의해 생성되어 공급됨 DaoFactory는 가장 단순한 IoC 프레임워크 IoC의 장점 프로그램 소스 코드의 유연성 및 확장성 증가 스프링과 IoC IoC는 스프링에서 제공하는 모든 기능의 기초가 되는 기반기술
23
스프링의 IoC
24
오브젝트 팩토리를 이용한 스프링 IoC 빈 (Bean) 빈 팩토리 (Bean Factory)
스프링이 제어권을 가지고 직접 생성하고 관계를 부여하는 수동적인 제어의 역전이 적용된 객체 빈 팩토리 (Bean Factory) 빈의 생성, 등록, 조회 및 관계설정 제어를 담당하는 IoC 객체 보통은 빈 팩토리를 직접 사용하지 않고 이를 확장한 어플리케이션 컨텍스트 (Application Context)를 이용함 스프링에 org.springframework.beans.factory.BeanFactory 인터페이스가 존재
25
오브젝트 팩토리를 이용한 스프링 IoC 애플리케이션 컨텍스트 (Application Context)
스프링에 org.springframework.context.ApplicationContext 인터페이스 존재 o.s.beans.factory.BeanFactory 상속 o.s.context.ApplicationContext
26
오브젝트 팩토리를 이용한 스프링 IoC 컨테이너 (Container) 또는 IoC 컨테이너 스프링 프레임워크
스프링이 제공하는 모든 기능을 통합하여 말할 때 사용하는 단어 스프링 컨테이너 ≒ IoC 컨테이너 ≒ 컨테이너 ≒ IoC 엔진 ≒ 애플리케이션 컨텍스트 ≒ 빈 팩토리
27
애플리케이션 컨텍스트의 동작방식 애플리케이션 컨텍스트의 역할
애플리케이션에서 IoC를 적용해서 관리할 모든 객체 대한 생성과 관계설정을 담당 하지만, 직접 객체를 생성하고 관계를 맺는 코드는 설정정보(Java or XML)를 통해 얻는다. Java나 XML Spring 설정파일에 각 Bean에 대한 정보를 기입한 후 사용 최근에는 Annotation기반으로 동작하기 때문에 Bean들을 각각 등록할 빈도가 줄어듬 XML Bean 등록 예 <bean id="userDao" class="koreatech.cse.dao.UserDao"> </bean>
28
애플리케이션 컨텍스트의 동작방식 애플리케이션 컨텍스트 활용 장점
클라이언트는 구체적인 팩토리 클래스(DaoFactory와 같은 사용자가 임의로 만든)를 사용할 필요가 없다. Java나 XML을 통한 IOC 방법 활용 종합적인 IoC 서비스를 제공받을 수 있다. 객체 자동생성, 객체 후처리, 설정 방식의 다변화
29
싱글톤 레지스트리와 오브젝트 스코프
30
싱글톤 레지스트리 DaoFactory 직접사용 vs. 애플리케이션 컨텍스트 사용
DaoFactory factory = new DaoFactory(); UserDao dao1 = factory.userDao(); UserDao dao2 = factory.userDao(); System.out.println(dao1); System.out.println(dao2); ApplicationContext context = new ClassPathXmlApplicationContext("services.xml"); UserDao dao1 = context.getBean(“userDao”, UserDao.class); UserDao dao2 = context.getBean(“userDao”, UserDao.class); System.out.println(dao1); System.out.println(dao2); 애플리케이션 컨텍스트는 각각의 빈에 대해 Singleton으로 저장하고 관리하는 Singleton Registry이다.
31
싱글톤 레지스트리로서의 애플리케이션 컨텍스트
클라이언트/서버 구조에서의 Singleton Registry를 사용하지 않는다면… 상황 가정 요청 한개당 5개의 객체 생성 초당 500번의 요청이 들어옴 결과 초당 2500개의 새로운 객체 생성 한 시간이면 9백만개의 새로운 객체 생성 자바의 Garbage Collection 성능이 아무리 좋아도 서버의 자원 사용량이 매우 높아짐
32
싱글톤 레지스트리로서의 애플리케이션 컨텍스트
스프링의 Singleton Registry private 생성자/static 필드 및 메소드가 없는 평범한 클래스 객체에 대해서도 Singleton으로 활용하게 해줌 즉, 고전적인 Singleton 패턴을 대신하여 Singleton 객체를 생성하고 관리해주는 레지스트리
33
스프링 빈의 스코프 빈 객체 Scope 스프링 빈 객체의 기본 Scope
빈 객체가 생성되고, 존재하고, 적용되는 시간/공간적인 범위 스프링 빈 객체의 기본 Scope Singleton Scope 컨테이너 내에 한 개의 객체로 생성 강제로 제거하지 않는 한 스프링 컨테이너 내에 계속해서 유지됨
34
의존관계 주입 (DI, Dependency Injection)
35
런타임 의존관계 설정 의존 관계 (Dependency) 의존관계 주입 (DI, Dependency Injection)
클래스의 의존관계 UML 다이어그램 “A가 B에 의존한다“ B의 기능이 추가 및 변경되거나 메소드 형식이 변경되면 그 영향이 A에게도 미침 의존관계에는 방향성이 있다. 의존관계 주입 (DI, Dependency Injection) 스프링에서 객체간의 관계설정 의도를 명확히 표현하는 용어 스프링을 다른 프레임워크와 차별화되어서 제공해주는 기능은 DI 라는 용어를 사용할 때 분명하게 드러남
36
런타임 의존관계 설정 스프링에서의 의존관계 주입 조건 클래스 모델이나 코드에서는 런타임 시점의 의존관계가 잘 드러나지 않는다.
DConnectionMaker가 들어올지, NConnectionMaker가 들어올지 모름 인터페이스를 사용하기 때문 런타임 시점의 의존관계는 애플리케이션 컨텍스트같은 제 3의 객체가 결정한다. 의존관계는 사용할 (의존할) 객체에 대한 레퍼런스를 제 3의 객체가 제공 (주입, DI)해줌으로써 만들어진다.
37
Annotation을 이용한 DI @Autowired @Inject
Spring Framework에서 지원하는 Dependency 정의 용도의 Annotation으로, Spring Framework에 종속적 @Inject JSR-330 표준 Annotation으로 Spring 3 부터 지원. 특정 Framework에 종속되지 않은 어플리케이션을 사용할 것을 권장. pom.xml에 다음과 같이 추가 --> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
38
활용 예 EmailService를 Inject받아 사용 @Controller
@RequestMapping(value = "/user") public class UserController { @Inject private Service Service; @RequestMapping @ResponseBody public String send () { String msg = "Hello, World!"; "This is test mail title", msg); return "Success"; }
Similar presentations