Hyokyun Yim bio photo

Hyokyun Yim

Koreatech Computer Science Engineering undergraduate 4 grade.

Facebook Github

Spring Framework 의 기본적인 개념에대해 공부해 보자.

Overview

Library vs Framework

  • 라이브러리란 자주사용하는 코드를 함수나 클래스로 묶어 놓고 가져다 쓰는것, 프로그램의 전체 설계에는 영향을 주지 않는다.
  • 즉 라이브러리라는 단순히 기능만 제공하는것 , 개발자의 능력에따라 같은 라이브러리를 사용해도 전체 설계는 차이가 있음
  • 프레임워크는 프로그램을 어떻게 짜야한다는 규칙이 있다. 내가 만들어야하는 파일, 폴더들이 다 제공이 되어있음
  • 즉 프레임워크는 이미 프로그램이 돌아가는 기반 틀이 만들어 져있고 개발자는 그 안에 코드를 집어 넣어서 프로그램을 만든다. -> 따라서 라이브러리와 달리 누가 하든지 간에 비슷한 코드품질을 가질 수 있다.
  • 따라서 회사 입장에서는 유지보수성과 재활용성이 높은 프레임워크 기반으로 프로그램을 만든다.
  • 좀더 쉽게 정리하면 라이브러리는 내 코드로 불러와 사용하는것이고, 프레임워크는 내 코드를 집어 넣어서 사용한다고 보면 된다.

Spring Framework

Composition

  • 하나의 객체가 다른 객체를 사용하는 방식
  • 하나의 객체가 다른 객체를 사용해야 하는데 이때 직접 객체를 생성해서 사용하는 방식. -> ex)Service가 메서드 내에서 DAO를 직접 만들어서 사용하는 방식
  • BookService와 BookDAO, 2개의 클래스 관계가 아주 밀접한 관계
  • 클래스간에 관계가 tightly coupled : 딱 결합이 되어 사용해야하는 관계, 즉 재사용성의 관점에서는 좋지 않다.
  • 하나의 클래스내에서 다른 클래스명이 명시적으로 등장하기 때문에 그렇다.
  • 아래 코드는 일반적인 Composition 방식의 예이다. Service 클래스의 메서드 내에 DAO 객체를 직접 생성함.
//Controller

public class BookController {

	Scanner s;
	
	public BookController()
	{
		s = new Scanner(System.in);
		System.out.print("키워드입력 =>");
		String keyword = s.nextLine();
		
		BookService service = new BookService();

		ArrayList<BookDTO> list = service.findBookByKeyword(keyword);
		
		for(BookDTO dto : list)
		{
		
			System.out.println(dto.getBtitle() +", " + dto.getBauthor());
			
		}
		
		
	}
}

//Service 

public class BookService {

	private BookDAO dao;
	
	
	public BookService(BookDAO dao) {
		this.dao = dao;
	}


	public BookDAO getDao() {
		return dao;
	}


	public void setDao(BookDAO dao) {
		this.dao = dao;
	}


	public ArrayList<BookDTO> findBookByKeyword(String keyword) {
		
		
		//composition 방식
		BookDAO dao = new BookDAO();

		return dao.select(keyword);
		
	}
}

Aggregation

  • 하나의 객체와 다른 객체를 결합해서 사용하는 방식
  • 그럼 어떻게 결합을 하는가? -> Service 내에 dao 필드를 만들고 , 조립자인 Controller를 이용한다.
  • 방법1: 조립자인 Controller 클래스가 Service 클래스의 getter/setter를 이용해 dao를 넘겨 객체들을 결합한다.
  • 방법2: 조립자인 Controller 클래스가 Service 클래스의 생성자를 이용하여 dao를 넘겨 객체들을 결합한다.
  • 아래코드는 Aggregation 방식의 예이다. getter/setter를 이용한 방식 그리고 생성자를 이용한 방식 2가지를 보여주고 있으며 Controller가 조립자 역할을 수행하고 있다.
//Controller

public class BookController {

	Scanner s;
	
	
	
	public BookController()
	{
		s = new Scanner(System.in);
		System.out.print("키워드입력 =>");
		String keyword = s.nextLine();
		
		
		//Aggregation
		//Service와 DAO를 결합하기위해 Controller에 DAO와 Service 객체를 만들고
		//setter 를 이용해 DAO를 service에 넘김. or 생성자 이용
		
		/*Aggregation 방법1
		BookDAO dao = new BookDAO();
		BookService service = new BookService();
		service.setDao(dao);
		*/
		
		//Aggregation 방법2
		BookDAO dao = new BookDAO();
		BookService service = new BookService(dao);
		

		ArrayList<BookDTO> list = service.findBookByKeyword(keyword);
		
		for(BookDTO dto : list)
		{
		
			System.out.println(dto.getBtitle() +", " + dto.getBauthor());
			
		}
		
		
	}
}

//Service

public class BookService {

	private BookDAO dao;
	
	
	public BookService(BookDAO dao) {
		this.dao = dao;
	}


	public BookDAO getDao() {
		return dao;
	}


	public void setDao(BookDAO dao) {
		this.dao = dao;
	}


	public ArrayList<BookDTO> findBookByKeyword(String keyword) {
		
		/*
		//composition 방식
		//BookDAO dao = new BookDAO();
		 */
		
		//transaction 은 데이터베이스가 수정이 되었을때 사용하는것 
		//select 시에는 필요 없다.
		return dao.select(keyword);
		
	}
	
	

}

Interface 기반의 Aggregation 방식

  • 비록 Composition 방식에서 Aggregation 방식으로 바꾸어 객체를 직접적으로 생성하지는 않지만, 아직도 Service 필드에 다른 클래스이름이 적혀있음 즉 DAO가 명시되어있다.
  • 이를 인터페이스를 이용하여 클래스간의 겹합도를 낮추는 작업을 수행한다.
  • 예를들어 DAO interface를 하나 만들고 이를 implements 하여 MySQL용 DAO 1개와, Oracle용 DAO 1개를 만들었다고 하자.
  • IS-A 관계가 성립되므로 Service 쪽에서는 필드에 인터페이스 DAO로 인스턴스를 하나 지정해놓고(ex: private DAO dao;) Controller 단에서 Orale용 DAO 또는 MySQL용 Dao를 service 생성자인자로 넘겨주면 된다.
  • 그러면 코드를 많이 바꿀필요없이 느슨한 결합으로 코드 구성이 가능하다 .
//Controller

package exam_01_01_composition.controller;

import java.util.ArrayList;
import java.util.Scanner;

import exam_01_01_composition.DAO.BookDAO;
import exam_01_01_composition.DAO.BookDAOOracle;
import exam_01_01_composition.DTO.BookDTO;
import exam_01_01_composition.service.BookService;

public class BookController {

	Scanner s;
	
	
	
	public BookController()
	{
		s = new Scanner(System.in);
		System.out.print("키워드입력 =>");
		String keyword = s.nextLine();
		
		
		//Aggregation
		//Service와 DAO를 결합하기위해 Controller에 DAO와 Service 객체를 만들고
		//setter 를 이용해 DAO를 service에 넘김. or 생성자 이용
		//생성자 이용 방식
		
		
		//★★★★ interface를 이용해 dao를 구성하였으므로
		//아래처럼 Controller 단에서 DB에 맞는 인스턴스만 생성해 Service에 넘기면됨
		//물론 Service 단에 필드로 DAO 인스턴스를 만들어 놔야함.
 		
		//BookDAO dao = new BookDAO();
		BookDAOOracle dao = new BookDAOOracle();
		BookService service = new BookService(dao);
		
		
		
		ArrayList<BookDTO> list = service.findBookByKeyword(keyword);
		
		for(BookDTO dto : list)
		{
		
			System.out.println(dto.getBtitle() +", " + dto.getBauthor());
			
		}
		
		
	}
}

//Service

package exam_01_01_composition.service;

import java.util.ArrayList;

import exam_01_01_composition.DAO.BookDAO;
import exam_01_01_composition.DAO.DAO;
import exam_01_01_composition.DTO.BookDTO;

public class BookService {

	//★★ 필드에 interface DAO로 인스턴스 생성
	private DAO dao;
	
	
	public BookService(DAO dao) {
		this.dao = dao;
	}


	public DAO getDao() {
		return dao;
	}


	public void setDao(BookDAO dao) {
		this.dao = dao;
	}


	public ArrayList<BookDTO> findBookByKeyword(String keyword) {
		
		return dao.select(keyword);
		
	}
	
	

}


//Interface DAO

package exam_01_01_composition.DAO;

import java.util.ArrayList;

import exam_01_01_composition.DTO.BookDTO;

public interface DAO {

	ArrayList<BookDTO> select(String keyword);

	

}

//MYSQL DAO

package exam_01_01_composition.DAO;

import exam_01_01_composition.DTO.BookDTO;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;


public class BookDAO implements DAO {

	
	
	public ArrayList<BookDTO> select(String keyword) {

		//제네릭을 이용해 BookDTO형 ArrayList만듬
		ArrayList<BookDTO> list = new ArrayList<BookDTO>();

		try{
			//1. 드라이버 로딩
			//자바프로그램이 MySQL에 접근하기 위해서 필요한 라이브러리를 불러들인다.
			//pom.xml 에 MySQL에 대한 dependency를 입력해서 라이브러리를 다운로드 받는다.
			Class.forName("com.mysql.jdbc.Driver");
			
			//2. 실제 데이터베이스에 접속
			//어떤 데이터베이스에 접속할 건지, 아이디와 패스워드가 필요
			String url = "jdbc:mysql://localhost:3306/library";
			String id = "root";
			String pw = "cps431";
			Connection con = DriverManager.getConnection(url,id,pw);	
			
			//3. SQL문을 실행하기 위한 Statement를 생성한다.
			String sql ="select btitle,bauthor from book where btitle like ?";
			PreparedStatement pstmt = con.prepareStatement(sql);
			
			//sql문에 내가 원하는 문자열을 넣는 작업
			//첫번째 물음표에 , keyword를 넣는다.
			//% 와일드문자는 0개이상의 문자를 의미한다. 즉 keyword를 포함하고 있는 문자열을 ?에 넣는다.
			pstmt.setString(1,"%"+ keyword + "%"); 
			
			
			//4. Statement 실행!!
			//수행한 쿼리문의 결과를 가져옴
			//rs 는 테이블 라인을 가리키는 포인터. 한칸씩 내려가면서 라인을 가리킴
			ResultSet rs = pstmt.executeQuery();
			
			//5. 결과처리
			//여기서 얻은 데이터를 어떻게 해서든 Controller 까지 전달하여 출력
			//DTO가 책 1권에 대한 데이터를 담을 수 있으니까.. DTO를 여러개 만들어서 결과로 나온 여러권의 책을 담아서 
			//Controller에게 전달한다!!
			while(rs.next())
			{
				//한 책에대한 정보가 담긴 rs를 dto에 때려박음
				BookDTO dto = new BookDTO();
				dto.setBtitle(rs.getString("btitle"));
				//dto.setBisbn(rs.getString("bisbn"));
				//dto.setBprice( rs.getInt("bprice")  );
				dto.setBauthor(rs.getString("bauthor"));
				
				//한권의 책정보 dto를 리스트에 넣음
				list.add(dto);
				
			}
		
			//6. 사용한 리소스 정리
			rs.close();
			pstmt.close();
			con.close();
			
			
		}catch(Exception e){
			//만약 오류가 생기면 오류 출력
			System.out.println(e);
		}
		
		
		return list;
	}

}


//Oracle DAO

package exam_01_01_composition.DAO;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;

import exam_01_01_composition.DTO.BookDTO;

public class BookDAOOracle implements DAO {

	
	public ArrayList<BookDTO> select(String keyword) {

		//제네릭을 이용해 BookDTO형 ArrayList만듬
		ArrayList<BookDTO> list = new ArrayList<BookDTO>();

		try{
			//1. 드라이버 로딩
			//자바프로그램이 MySQL에 접근하기 위해서 필요한 라이브러리를 불러들인다.
			//pom.xml 에 MySQL에 대한 dependency를 입력해서 라이브러리를 다운로드 받는다.
			Class.forName("com.oracle.jdbc.Driver");
			
			//2. 실제 데이터베이스에 접속
			//어떤 데이터베이스에 접속할 건지, 아이디와 패스워드가 필요
			String url = "jdbc:orcle://localhost:1582/library";
			String id = "root";
			String pw = "cps431";
			Connection con = DriverManager.getConnection(url,id,pw);	
			
			//3. SQL문을 실행하기 위한 Statement를 생성한다.
			String sql ="select btitle,bauthor from book where btitle like ?";
			PreparedStatement pstmt = con.prepareStatement(sql);
			
			//sql문에 내가 원하는 문자열을 넣는 작업
			//첫번째 물음표에 , keyword를 넣는다.
			//% 와일드문자는 0개이상의 문자를 의미한다. 즉 keyword를 포함하고 있는 문자열을 ?에 넣는다.
			pstmt.setString(1,"%"+ keyword + "%"); 
			
			
			//4. Statement 실행!!
			//수행한 쿼리문의 결과를 가져옴
			//rs 는 테이블 라인을 가리키는 포인터. 한칸씩 내려가면서 라인을 가리킴
			ResultSet rs = pstmt.executeQuery();
			
			//5. 결과처리
			//여기서 얻은 데이터를 어떻게 해서든 Controller 까지 전달하여 출력
			//DTO가 책 1권에 대한 데이터를 담을 수 있으니까.. DTO를 여러개 만들어서 결과로 나온 여러권의 책을 담아서 
			//Controller에게 전달한다!!
			while(rs.next())
			{
				//한 책에대한 정보가 담긴 rs를 dto에 때려박음
				BookDTO dto = new BookDTO();
				dto.setBtitle(rs.getString("btitle"));
				//dto.setBisbn(rs.getString("bisbn"));
				//dto.setBprice( rs.getInt("bprice")  );
				dto.setBauthor(rs.getString("bauthor"));
				
				//한권의 책정보 dto를 리스트에 넣음
				list.add(dto);
				
			}
		
			//6. 사용한 리소스 정리
			rs.close();
			pstmt.close();
			con.close();
			
			
		}catch(Exception e){
			//만약 오류가 생기면 오류 출력
			System.out.println(e);
		}
		
		
		return list;
	}
	
	
}


IoC(Inversion of Control - 제어의 역전)

  • 기존 Composition(일반적인 프로그램 흐름)방식과 비교되는 방식
  • 기존 제어 흐름을 거꾸로 뒤집는 개념
  • 객체는 자신이 사용할 객체를 스스로 선택하지도 생성하지도 않는다. -> Interface 기반의 Aggregation 방식
  • 객체는 자신도 어떻게 만들어지고 어디에서 사용되는지 알 수 없다.
  • 모든 제어 권한을 자신이 아닌 다른 대상에게 위임하기 때문
  • 모든 겍체는 제어 권한을 갖는 특별한 객체에 의해서 생성되고 사용이 결정된다.
  • 일반적으로 Framework 라고하면 IoC의 개념이 적용되어있다. -> 즉 객체를 조합할 수 있는 기능을 가지고 있어야한다.
  • 객체를 결합하는 과정을 Spring이 해준다.

DI(Dependency Injection - 의존성 주입)

  • 종속객체(DAO) : Service에서 사용되는 객체
  • 종속객체(Dependency)를 사용할려는 객체에 주입(Injection)하려는 행동
  • Spring은 Dependency Injection을 처리해주는 Container 역할을 한다.