토비의 스프링3 - 1부 이해 1.4~1.5

2020. 5. 26. 14:29자바 Java/스프링(Spring) 프레임워크

반응형

1.4 제어의 역전(IoC : Inversion of Control)  1.5 스프링의 IoC

 

앞에서 만들었던 코드에서 기능을 분리해서 만들고 싶다. 

UserDao와 ConnectionMaker 구현 클래스의 오브젝트를 만드는 것과, 

그렇게 만들어진 두개의 오브젝트가 연결돼서 사용 될수 있도록 관계를 만들어 주는 것이다. 

 

package springbook.user.dao;

public class DaoFactory {
	public UserDao userDao() {
		ConnectionMaker connectionMaker = new DConnectionMaker();
		UserDao userDao = new UserDao(connectionMaker);
		return userDao;
	}
}

 

package springbook.user.dao;
import java.sql.SQLException;
import springbook.user.domain.User;
public class UserDaoTest {

	public static void main(String[] args) throws ClassNotFoundException, SQLException {
		UserDao dao = new DaoFactory().userDao();
		User user = new User();
		user.setId("iluvdori");
		user.setName("토끼와거북");
		user.setPassword("queen");
		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() + " 조회 성공");
	}
}

 

 

이렇게 되면 UserDao는 변경이 필요 없으므로 안전하게 소스코드 보존하면서 동시에 DB 연결 방식은 자유로운 확장이 가능하다 .

이렇게 DaoFactory 를 분리 했을때, 애플리케이션의 컴포넌트 역할을 하는 오브젝트와 애플리케이션의 구조를 결정하는 오브젝트를 분리했다는데 큰 의미가 있다. 

 

 

이제, 오브젝트 팩토리를 활용해보자 

만약 DaoFactory dp UserDao가 아닌 다른 DAO생성기능을 넣으면 어떻게 될까?

 

 

DAO 생성 메소드의 추가로 인해 발생 하는 중복 

 

중복 문제를 해결하는 것은 분리 이다. 

ConnectionMaker 의 구현 클래스를 결정하고 오브젝트를 만드는 코드를 별도의 메소드로 뽑아내자. 

DAO를 생성하는 각 메소드에서는 새로만든 ConnectionMaker 생성용 메소드를 이용하도록 수정한다. 

리팩토링 방법이다. 

이렇게 하면 아무리 DAO팩토리 메소드가 많아져도 문제 없다. 

 

아래는 수정한 코드이다. 

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();  // -> 분리해서 중복을 제거한 ConnectionMaker 타입 오브젝트 생성코드 
    }
}

 

위의 예들은 

제어권의 이전을 통한 제어관계 역전을 보여준다. 

일반적으로 프로그램의 흐름은 main() 메소드와 같이 프로그램이 시작되는 지점에서 다음에 사용할 오브젝트를 결정하고 결정한 오브젝트를 생성하고, 만들어진 오브젝트에 있는 메소드를 호출하고 그 오브젝트 메소드 안에서 다음에 사용할 것을 결정 하는 등  각 오브젝트는 작업에 능동적으로 참여한다. 즉 모든 오브젝트가 능동적으로 자신이 사용할 클래스를 결정하고, 언제 그 오브젝트를 만들지를 스스로 관장한다 모든 종류의 작업을 사용하는 쪽에서 제어하는 구조이다. 

제어의 역전이란 이런 제어 흐름을 거꾸로 뒤집는 것이다. 

모든 제어 권한을 자신이 아닌 다른 상대에게 위임하기 때문이다. 

프로그램의 시작을 담당하는 main() 과 같은 엔트리 포인트를 제외하면 모든 오브젝트는 위임받은 제어권한을 갖는 특별한 오브젝트에 의해 결정되고 만들어진다. 

 

프레임워크도 제어의 역전개념이 적용된 대표적인 기술이다. 프레임 워크와 라이브러리는 다르다. 

라이브러리를 사용하는 애플리케이션 코드는 애플리케이션 흐름을 직접 제어한다. 단지 동작하는 중에 필요한 기능이 있을때 능동적으로 라이브러리를 사용할 뿐이다. 반면에 프레임 워크는 거꾸로 애플리케이션 코드가 프레임 워크에 의해 사용된다. 보통 프레임 워크 위에 개발한  클래스를 등록해 두고, 프레임워크가 흐름을 주도하는 중에 개발자가 만든 애플리케이션 코드를 사용하도록 만드는 방식이다. 

프레임워크에는 분명한 제어의 역전 개념이 적용되어 있어야 한다. 애플리케이션 코드는 프레임워크가 짜놓은 틀에서 수동적으로 동작해야한다. 

 

IoC를 적용함으로써 설계가 깔끔해지고 유연성이 증가하며 확장성이 좋아지기 때문에 필요할 때면 IoC 스타일의 설계외 코드를 만들어 사용하면 된다. 

 

제어의 역전에서는 프레임워크 또는 컨테이너와 같은 애플리케이션 컴포넌트의 생성과 관계설정, 사용, 생명 주기  관리 등을 관장하는 존재가 필요하다. 

 

 

 

1.5 스프링의 IoC 

기존 DaoFactory 코드에는 설정정보, 예를 들면 어떤 클래스의 오브젝트를 생성하고 어디에서 사용하도록 연결해 줄것인가 등에 관한 정보가 평범함 자바 코드로 만들어져 있다. 애플리케이션 컨텍스트는 직접 이런 정보를 담고 있지 않고, 별도로 설정정보를 담고 있는 무엇인가를 가져와 이를 활용하는 범용적인 IoC 엔진 같은 것으로 볼 수 있다. 

 

앞의 다이어그램을 보면 애플리케이션의 로직을 담고 있는 컴포넌트와 설계도 역할을 하는 팩토리를 구분 했었다. 

바로 이 설계도 라는게 이런 어플리케이션 컨텍스트와 그 설정정보를 말한다고 보면 된다. 그 자체로는 애플리케이션 로직을 담당하지는 않지만 IoC방식을 이용해 애플리케이션 컴포넌터를 생성하고, 사용할 관계를 맺어주는 등의 책임을 담당하는 것이다. 

마치 건물이 설계도면을 따라서 만들어지듯이, 애플리케이션도 애플리케이션 컨텍스트와 그 설정정보를 따라서 만들어지고 구성된다고 생각 할 수 있다. 

 

아래는  애노테이션이 적용된 DaoFactory 클래스 이다. 자바코드로 작성되어 있지만 사실은 XML과 같은 스프링 전용 설정 정보라고 보는 것이 좋다. 

 

DaoFactory를 스프링의 빈팩토리가 사용할 수 있는 본격적인 설정정보로 만들어보자

@configuration 이라는 애노테이션 추가 => 스프링이 빈 팩토리를 위한 오브젝트 설정을 담당하는 클래스로 인식 

@Bean  이라는 애노테이션 추가 => 오브젝트를 만들어주는 메소드 

이 두가지 애노테이션만으로 스프링 프레임워크의 빈팩토리 또는 애플리케이션 컨텍스트가 IoC방식의 기능을 제공할 때 사용할 완벽한 설정정보가 된 것이다. 

package springbook.user.dao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration  // -> 애플리케이션 컨텍스트 또는 빈 팩토리가 사용할 설정정보라는 표시 
public class DaoFactory{
	@Bean
	public UserDao userDao(){
    	return new UserDao(connectionMaker());
    }
	@Bean // -> 오브젝트 생성을 담당하는 IoC용 메소드라는 표시 
    public ConnectionMaker connectionMaker(){
    	return new DConnectionMaker(); 
    }
}

 

 

package springbook.user.dao;
import java.sql.SQLException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
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);
		User user = new User();
		user.setId("iluvdori");
		user.setName("토끼와거북");
		user.setPassword("queen");
		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() + " 조회 성공");
	}
}

DaoFactory를 설정정보로 사용하는 애플리케이션 컨텍스트를 만들때에 ApplicationContext타입의 오브젝트를 사용한다. 

ApplicationContext를 구현 한 클래스는 여러 가지가 있는데 @Configuration이 붙은 자바코드를 설정정보로 사용하려면

AnnotationConfigApplicationContext를 이용하면 된다. 

생성자 파라미터로 DaoFactory 클래스를 넣어준다. 

이렇게 준비된 ApplicationContext의 ApplicationContext가 관리하는  오브젝트를 요청하는 메소드인 getBean() 메소드를 이용해 UesrDao 의 오브젝트 가져올수 있다. 

getBean()의 파라미터인 userDao 는  ApplicationContext에 등록된 빈의 이름이다. 

@Bean 이라는 애노테이션이 붙은 메소드의 이름이 빈의 이름이 된다. 

 

 

getBean() 메소드는 기본적으로 Object 타입으로 리턴 하게 되어있어 매번 리턴되는 오브젝트에 다시 캐스팅 해줘야 하는 부담이 있다. 

자바5 이상의 제네릭메소드(generic method) 방식을 사용해 getBean() 의 두번째 파라미터에 리턴타입을 주면, 지저분한 캐스팅 코드를 사용하지 않아도 된다. 

 

 

 

 

 

 

 

 

<용어정리>

 

팩토리 : 객체의 생성 방법을  결정하고 그렇게 만들어진 오브젝트를 돌려주는 일을 하는 오브젝트를 의미 

(디자인패턴에서 말하는 특별한 문제를 해결하기 위해 사용되는 추상 팩토리 패턴이나 팩토리 메소드 패턴과는 다르니 혼동하지 말자.) 

 

빈(bean): 빈 또는 빈 오브젝트는 스프링이 IoC방식으로 관리하는 오브젝트라는 뜻이다. 관리되는 오브젝트라고 부르기도 한다. 

스프링에서는 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 빈이라고 한다. 자바빈 또는 엔터프라이즈 자바빈(EJB)에서 말하는 빈과 비슷한 오브젝트 단위의 애플리케이션 컴포넌트를 말한다. 동시에 스프링 빈은 스프링 컨테이너가 생성과 관계설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트를 가리키는 말이다. 주의할 점은 스프링을 사용하는 애플리케이션에서 만들어지는 모든 오브젝트가 다 빈은 아니다. 스프링이 직접 그 생성과 제어를 담당하는 오브젝트만 빈이다.

 

빈 팩토리(bean factory) : 스프링의 IoC를 담당하는 핵심 컨테이너로  빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트.

보통 빈 팩토리를 바로 사용하지 않고 이를 확장한 애플리케이션 컨텍스트를 이용. 

 BeanFactory라고 붙여쓰면 빈팩토리가 구현하고 있는 가장 기본적인 인터페이스의 이름이된다. 이 인터페이스에 getBean() 과 같은 메소드가 정의되어 있다. 

 

애플리케이션 컨텍스트(application context) : 빈팩토리를 확장한 IoC 컨테이너. IoC방식을 따라 만들어진 일종의 빈팩토리.  별도의 정보를 참고해서 빈(오브젝트)의 생성, 관계 설정등의 제어 작업을 총괄 한다. 

ApplicationContext라고 적으면 애플리케이션 컨텍스트가 구현해야하는 기본 인터페이스를 가르키는 것이기도하다. 

ApplicationContext는 BeanFactory를 상속한다. 

[빈팩토리와 애플리케이션 컨텍스트는 동일하다고 생각하며 된다. 초점을 맞춘 부분이 다를 뿐이다. 빈 팩토리라고 말할때는 빈을 생성하고 관계를 설정하는 IoC의 기본 기능에, 애플리케이션 컨텍스트라고 말할 때는 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진기능에 초점을 맞춘다. ]

 

설정정보/설정 메타정보 (configuration metadata)

스프링의 설정정보란 애플리케이션 컨텍스트 또는 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타정보 

영어로 configuration라고 하는데 구성정보 내지는 형상 정보 라는 의미. 

실제로 스프링의 설정정보는 IoC 컨테이너에 의해 관리되는 애플리케이션 오브젝트를 생성하고 구성할때 사용 

애플리케이션의 형상 정보, 청사진 이라고도 한다. 

 

컨테이너 또는 IoC컨테이너 

IoC방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨태이너 또는 IoC컨테이너 라고 ㅎ나다. 

 

 

스프링 프레임워크 

IoC컨테이너, 애플리케이션 컨텍스트를 포함해 스프링이 제공하는 모든 기능을 통틀어 말할때 주로 사용, 그냥 스프링이라고도 함. 

반응형