Dependency Injection(의존성 주입)
객체간의 의존성을 자신이 아닌 외부에서 주입하는 개념이다.
스프링에서 이런 개념을 사용하는데에는 이유가 있을 것이다.
의존성 주입이 왜 필요할까? 이걸 사용하게 되면 무엇이 편할까? 아니, 그 전에 의존성이란 무엇일까?
나는 처음 공부할때 이런 것들이 궁금했다.
우선 가장 간단한 예제를 들어보자.
아래의 HelloApp은 MessageBean이라는 클래스에서 sayHello라는 메소드를 호출한다.
실행 결과 : Hello, Spring!
package sample1;
/**
* Created by james on 16. 2. 10.
*/
public class HelloApp {
public static void main(String[] ars){
MessageBeanEn bean = new MessageBeanEn();
bean.sayHello("Spring");
}
}
package sample1;
/**
* Created by james on 16. 2. 10.
*/
public class MessageBeanEn {
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
}
간단하다.
하지만 소프트웨어에는 변화가 불가피하다는 불변의 진리가 있다.
그리고 소프트웨어 기능 변경은 곧 코드의 변화와 연결된다.
기능이 추가될 때마다 매번 코드를 변경하고, 다시 컴파일하는 것은 비용이 많이 들게 되므로, 가급적이면 코드의 변화가 적어지도록 프로그램을 작성하는게 유지보수 측면에서 유용할 것이다.
어떻게 하면 소스 코드의 변경을 최소화 할 수 있을까?
반대로 생각해 본다면, 어떤 경우에 소스 코드의 변경이 자주 일어날까?
기존의 Hello Spring을 출력하는 기능에서 한글로 안녕 스프링!을 출력해 본다.
package sample1;
/**
* Created by james on 16. 2. 10.
*/
public class HelloApp {
public static void main(String[] ars){
MessageBeanKr bean = new MessageBeanKr(); //MessageBeanEn -> MessageBeanKr로 변경
bean.sayHello("Spring");
}
}
package sample1;
/**
* Created by james on 16. 2. 10.
*/
public class MessageBeanKr {
public void sayHello(String name) {
System.out.println("안녕, " + name + "!");
}
}
메인의 MessageBeanEn을 MessageBeanKr로 바꿔줘야 한다.
이런 경우에 HelloApp이 MessageBeanEn(Kr)에 의존성을 가지고 있다고 한다.
HelloApp의 기능을 바꾸고자 할 때 MessageBean도 함께 바꿔줘야 하기 때문이다.
이러한 의존성을 해결해주기 위해서는 객체의 인스턴스를 외부에서 생성받을 필요가 있다.
마틴 파울러가 저술한 Inversion of Control Containers and the Dependency Injection pattern에서는 의존성 주입을 아래의 3가지로 분류한다.
이중 스프링이 지지하는 방식은 2. setter메소드를 이용한 의존성 주입이라고 하는데.. 예제와 자세한 설명은 아래 블로그를 참조하면 좋을 것 같다.
http://www.nextree.co.kr/p11247/
두번째 코드를 보자.
MessageBeanKr과 MessageBeanEn에 대한 인터페이스를 구현하여 그 전보다 HelloApp의 소스 변경을 줄였다.
출력되는 내용을 영문으로 변경하고 싶으면 구현체를 MessageBeanEn으로 바꿔주기만 하면 된다.
package sample1;
/**
* Created by james on 16. 2. 10.
*/
public interface MessageBean {
public void sayHello(String name);
}
package sample1;
/**
* Created by james on 16. 2. 10.
*/
public class MessageBeanKr implements MessageBean{
public void sayHello(String name) {
System.out.println("안녕하세요, " + name + "씨.");
}
}
package sample1;
/**
* Created by james on 16. 2. 10.
*/
public class MessageBeanEn implements MessageBean{
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
}
package sample1;
/**
* Created by james on 16. 2. 10.
*/
public class HelloApp {
public static void main(String[] ars){
MessageBean bean = new MessageBeanKr();
bean.sayHello("Spring"); //위의 대입문을 MessageBeanEn으로 바꾸면 영문이 출력된다.
}
}
하지만 이 역시 소스코드의 변경이 약간은 일어나게 된다.
마지막 코드를 보자.
아래와 같은 설정 파일이 추가되었다. 이 파일은 외부에서 MessageBean에 주입할 객체에 대한 설정 정보가 담겨있다.
beans.xml
<?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">
<!--class를 MessageBeanEn으로 바꾸면 영문이 출력된다-->
<bean id="messageBean" class="sample1.MessageBeanKr" />
</beans>
HelloApp.java
package sample1;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
/**
* Created by james on 16. 2. 10.
*/
public class HelloApp {
public static void main(String[] ars){
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("resources/beans.xml"));
//bean이 사용하는 클래스 이름(MessageBeanEn 혹은 MessageBeanKr)을 코드에 직접 기술하지 않는다. 즉, 의존성이 없다.
MessageBean bean = factory.getBean("messageBean", MessageBean.class);
bean.sayHello("Spring");
}
}
결과는 아래와 같이 출력된다.
안녕하세요, Spring 씨
만약 출력되는 코드를 영문으로 바꾸고 싶다면 beans.xml에서 아래 부분을
<bean id="messageBean" class="sample1.MessageBeanKr" />
다음과 같이 바꾸면 된다.
<bean id="messageBean" class="sample1.MessageBeanEn" />
그러면 출력되는 결과는
Hello, Spring! 이 될 것이다.
소스 코드의 변경 없이 환경설정만으로도 프로그램을 제어할 수 있다.
이것이 가능한 이유는 객체의 생명주기를 스프링 컨테이너가 관리하는 IoC개념이 있기 때문이다.
결론 : 스프링에서의 의존성 주입은 객체의 실체를 외부 환경설정(spring config xml, Bean 객체 등) 에서 컨트롤 할 수 있도록 하는 것이라고 생각한다.
왜? : 모듈 간의 결합도를 낮춰서 유연한 변경을 가능하도록 하기 위하여
[프로젝트 오일러] 50자리 숫자 100개를 더한 값의 첫 10자리 구하기 (0) | 2016.04.17 |
---|---|
스프링 프레임워크란 무엇인가? (0) | 2016.04.17 |
[프로젝트 오일러] 세자리 수를 곱해 만들 수 있는 가장 큰 대칭수 (Largest palindrome product) (0) | 2015.12.28 |
intellij 에서 Auto publishing 설정하기 (0) | 2015.12.26 |
새로운 프로그래밍 언어로 어떤 것을 배울까.. (0) | 2015.12.23 |
댓글 영역