IoC (Inversion Of Control) : 제어역전

 

 

어떠한 제어권을 역전한다는 이야기냐...?

 

어떠한 객체를 생성하거나, 그 객체를 셋팅하거나, 객체를 활용하여 작업을 한다거나 ..

이 모든것은 개발자가 해왔다. spring을 사용해본적이 없는 나는 이게 아주 당연하다고 생각했다.

 

그런데

 

IoC는 개발자가 몇가지 셋팅만으로 전체 프로그램을 제어하는 제어권을 프레임워크가 가지는 것을 의미한다.

개발을 하다보면 반복되는 작업이 많은데 그런것을 프레임워크에 미리 구현을 해둔것.

'개발자는 어떠한 클래스를 이용해서 객체를 만들것이다' 와 같은 프레임워크가 판단할수 없는 것만 설정해주면 된다!

 

 

 

 

 

 

+ 2021-12-10 내용추가

 

스프링 핵심원리를 다시 공부하다가 보니까 설명을 너무 간단하게 한 것 같아서 추가해본다.

 

개발자의 입장에서 봤을 때 객체를 생성하고, 연결하고, 실행하는 흐름이 자연스러운 흐름이다. 우리가 예를 들어 스프링에서 AppConfig(DI컨테이너)처럼 구성을 담당하는 클래스를 사용함으로써 클라이언트가 직접 객체를 생성하고 연결, 실행하는 흐름이 아닌 AppConfig에서 인터페이스의 구현클래스를 설정하고 객체를 생성한다. 프로그램에 대한 제어의 흐름은  AppConfig가 모두 가지고 있는 것이며 인터페스들의 구현클래스는 그 역할에 대한 구현을 수행하는 로직만을 실행하게 된다. 

이처럼 개발자가 흐름을 제어하는 것이 아니라 외부에서 흐름의 제어권을 가지게 되는 것을 제어의 역전이라고 한다.

 

 

 

 

 

 

프레임워크와 라이브러리

 

이 둘의 차이점은 무엇일까?

예를 들어, JUnit과 같은 프레임워크는 내가 작성한 코드를 제어하고 어떤 내부적인 로직을 통해서 코드를 대신 실행해주기 때문에 프레임워크가 맞다.

그러나 jQuery와 같은 라이브러리는 내가 코드를 작성하면서 필요할 때 사용함으로써 제어의 흐름을 내가 담당하기 때문에 프레임워크가 아니라 라이브러리이다.

 

 

 

 

 

 

POJO Class (Plain Old Java Object)

 

 

들어는 봤는데 명확하지 않았던 용어.

 

자바모델이나 기능, 프레임워크 등에 따르지 않고 홀로 독립적으로 단순한 기능만 가지는 객체들을 의미한다.

자바에서는 이러한 객체들을 Bean이라고도 부른다.

 

예를 들어서.. DB와 연동되는 소프트웨어를 구현한다고 하면

프레임워크에 영향을 받지 않는.. DAO나 VO같은 클래스가 POJO 클래스가 된다고 할 수 있겠다.

또한 학사관리 시스템을 만든다면, 학교정보나 학생들의 정보가 있는 클래스가 POJO클래스라고 할 수 있을 것.

 

 

위의 그림에서 IoC의 특징을 알 수 있었다.

제어권은 프레임워크에 있기 때문에 POJO클래스를 활용하여 스프링 컨테이너에서 작업을 진행할 때, 프로그램이 흘러가는 흐름에 대한 정보같은 것을 사용자가 만들어 주면 되겠다.

 

사용자가 정의한 데이터의 흐름, 위 그림에서 보이는 Metadata는 Xml 또는 자바로 만들 수 있겠다.

 

 

 

IoC 컨테이너의 종류

1. BeanFactory

2. ApplicationContext

 

 

 

1. BeanFactory

BeanFactory는 스프링 3.0이상에서는 더이상 사용되지 않고 ApplicationContext로 대체되고 있지만, 실제 업무에서는 스프링버전이 다양할 수 있기 때문에.. BeanFactory도 알아보자..!

 

- 클래스를 통해 객체를 생성, 전달

- 상속 등 객체관의 관계를 형성, 관리

 

이정도의 기능이 있다고 한다. 말로만 봐서는 그냥 '그렇군.' 싶은데 .. 코드로 봐야겠다.

 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="test1" class="com.study.spring.beans.TestBean" />
</beans>

 

 

 

beans.xml 파일이다.

test1이라는 이름의 빈을 한개 만들었고 클래스패스를 입력해주었다.

 

 

 

public static void test1() {
	ClassPathResource resource = new ClassPathResource("com/study/spring/config/beans.xml");
	XmlBeanFactory factory = new XmlBeanFactory(resource);

	TestBean t1 = factory.getBean("test1", TestBean.class);
	System.out.printf("t1 : %s\n", t1);

	TestBean t2 = factory.getBean("test1", TestBean.class);
	System.out.printf("t1 : %s\n", t2);
}

 

 

 

BeanFactory에서 빈을 활용하기 위해서는 ClassPathResource 를 사용하여 빈을 만든 xml의 path를 정의해준다.

XmlBeanFactory 에 ClassPathResource에서 만든 변수를 넣어줌으로서 활용이 가능하다.

factory.getBean하여 정의해준 bean 객체를 가지고 옴으로써 활용할 수 있겠다.

 

t2라는 변수를 한번더 테스트 해본 이유는 IoC컨테이너의 특성을 알아보기 위해서이다.

id가 test1인 bean객체를 가져올 때 객체가 생성되어 있지 않는 상태라면 객체를 생성한 후 주소값을 받고 그 객체를 버리지 않고 가지고 있다. (IoC컨테이너에서 컨테이너는 보관의 개념인가보다.)

그러므로 똑같은 id의 bean객체를 가져오면 두 결과는 같은 객체가 되겠다.

즉, 생성된 객체는 더이상 생성되지 않으며 Singleton이라고 할 수 있겠다.

 

 

 

 

그런데

 

만약 beans.xml파일이 패키지 내부가 아닌 패키지 외부에 있다면????

 

 

 

public static void test2() {
	FileSystemResource resource = new FileSystemResource("beans.xml");
	XmlBeanFactory factory = new XmlBeanFactory(resource);

	TestBean t1 = factory.getBean("test2", TestBean.class);
	System.out.printf("t1 : %s\n", t1);

	TestBean t2 = factory.getBean("test2", TestBean.class);
	System.out.printf("t2 : %s\n", t2);
}

 

 

ClassPathResource 대신에 FileSystemResource를 사용해주면 되겠다. 그리고 xml의 경로 역시 패키지의 경로를 제외하고 beans.xml만 써주면 된다.

 

 

 

 

 

 

 

 

2. ApplicationContext

BeanFactory보다는 더 많이 활용되는 ApplicationContext이다.

 

- 클래스를 통해 객체를 생성, 전달

- 상속 등 객체관의 관계를 형성, 관리

- Bean에 이벤트를 발생시킬 수 있음

.. 등등

 

BeanFactory가 가지고 있는 기능을 포함한 더 많은 기능을 가지고 있다.

 

 

 

public static void test3() {
	ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/study/spring/config/beans.xml");

	TestBean t1 = ctx.getBean("test1", TestBean.class);
	System.out.printf("t1 : %s\n", t1);

	TestBean t2 = ctx.getBean("test1", TestBean.class);
	System.out.printf("t2 : %s\n", t2);

	ctx.close();
}

 

 

ApplicationContext를 사용할 때에는 ClassPathXmlApplicationContext 를 사용하여 xml의 패스를 넣어주기만 하면 해당 bean객체를 자동으로 생성해준다.

 

자동으로 객체를 생성해주는 시점은 사용자가 변경해 줄 수 있다.

Default값은 getBean을 하지 않아도 자동으로 객체를 생성해주었다.

 

BeanFactory에서의 예제와 마찬가지로 ApplicationContext도 객체를 생성하고 보관하고 있기 때문에 t1과 t2는 같은 객체라는 결과를 얻을 수 있었다.

 

 

 

 

 

beans.xml이 패키지의 외부에 있다면??

 

 

 

public static void test4() {
	FileSystemXmlApplicationContext fctx = new FileSystemXmlApplicationContext("beans.xml");

	TestBean t1 = fctx.getBean("test2", TestBean.class);
	System.out.printf("t1 : %s\n", t1);

	TestBean t2 = fctx.getBean("test2", TestBean.class);
	System.out.printf("t1 : %s\n", t2);

	fctx.close();
}

 

 

ClassPathXmlApplicationContext 대신에 FileSystemXmlApplicationContext 를 사용하여 xml파일의 path를 지정해주면 되겠다.

'JAVA > Spring' 카테고리의 다른 글

컬렉션 주입  (0) 2020.04.09
의존성 주입 (Dependency Injection)  (0) 2020.04.09
Bean 객체의 생성시점과 생명주기  (0) 2020.04.08
Maven 설정  (0) 2020.04.07
스프링 MVC 프레임워크의 구조  (0) 2020.03.31

+ Recent posts