#Spring - 5. Dependency Injection(DI) 종속성 주입
본문 바로가기
Programming/Spring

#Spring - 5. Dependency Injection(DI) 종속성 주입

by 권가 2019. 6. 12.

1. Object Dependencies

PetOwner 객체는 AnimalType 객체(이 경우, Dog)에 따라 다르다.

이 접근방식의 문제는 아래와 같다.

PetOwner 객체는 AnimalType 객체의 생성을 제어함 
PetOwner 객체와 AnimalType 객체 간 긴밀하게 결합됨 
따라서 AnimalType 객체의 변경은 PetOwner 객체의 변경으로 이어질 것이다.

즉, 종속성을 주입해 자유롭게 하자!


2. Dependency Injection

 

Container이 Bean을 생성하고 종속성 주입 수행한다.

종속성 주입과 제어 역전은 서로 다르게 사용된다.
IoC(Inversion of Control)는 DI(Dependency Injection)를 통해 달성된다.

객체 자체보다는 프레임워크에 의해 객체의 종속성이 주입되는 설계 패턴이다.
그것은 프레임워크에 의해 동적으로 주입될 때 여러 물체들 사이의 종속관계 결합을 감소시킨다.


3. The Spring Container

스프링 프레임워크의 핵심 요소
Bean의 포함(Containing) 및 관리 담당
- 객체를 생성한다.
- 객체들을 서로 연결한다.
- 연결된 객체들을 설정한다.
- 객체들의 전체 수명주기를 관리한다.

즉, 객체들을 생성, 연결, 삭제하는 Spring Container은 연예인 기획사와 비슷하다 볼 수 있다.

구성 메타데이터는 다음 중 하나에 의해 표현될 수 있다.
- XML
- 자바 주석
- Java 기반 구성

즉, 위의 3가지 방법을 통해 Spring Container에게 알려준다.


Container은 응용 프로그램을 구성하는 Bean을 관리하기 위해 종속성 주입(DI)을 사용한다.

 

Spring은 두 종류의 컨테이너와 함께 온다.
- Bean팩토리
- ApplicationContext

<- 모바일- BeanFactory ApplicationContext -서버->

가장 간단하며 주로 DI를 위한 Factory
보다 발전되고 복잡한 Factory

리소스 제한이 있을 시 사용한다.
예: 모바일, 애플릿 등
다른 곳에서 사용되며 다음과 같은 기능이 있음
1. 엔터프라이즈 인식 기능
2. Listener들에게 응용 프로그램 이벤트 제공(publish)
3. 요청 시 bean을  연결 또는 삭제한다.

 

org.springframework.beans.factory.BeanFactory

org.springframework.context.ApplicationContext

XMLBeanFactory

ClassPathXmlApplicationContext

ApplicationContext context = new ClassPathXmlApplicationContext("com/kwonga/spring/beans/bean.xml");

HelloWorld obj = (HelloWorld) context.getBean("helloWorld");

설정된 XML로 Container가 Bean을 생성, 연결, 삭제한다.


3. Spring Container and DI

Example for DI(Dependency Injection)


Bean 구성 & 종속성


DI(Dependency Injection)의 장점

종속성 감소된다
- 구성 요소 종속성이 감소되면 변경에 대한 취약성이 감소한다.

재사용 가능한 코드 추가
- 어떤 인터페이스의 다른 구현이 다른 맥락에서 필요한 경우, 구성요소는 그 구현과 함께 작동하도록 구성할 수 있다. 코드를 변경할 필요가 없다.

 

더 많은 추가 테스트 가능한 코드
- 종속성이 구성요소에 주입될 수 있는 경우, 이러한 종속성의 모의 구현을 주입할 수 있다. Mock 객체는 실제 구현을 위한 대체물로 테스트에 사용된다.
- 예를 들어, 모형이 올바른 객체를 반환할 때, null이 반환되어 예외가 던져질 때 두 가지를 모두 처리한다.

더 읽기 쉬운 코드
- 이를 통해 구성 요소의 종속성을 보다 쉽게 확인할 수 있어 코드를 보다 쉽게 읽을 수 있다.


4. What are Beans?

Spring에서 POJO(Plain Old Java Object)를 'bean'이라고 하며, 이러한 객체들은 IoC 컨테이너에 의해 인스턴스화, 관리, 생성된다.
Bean들은 컨테이너에 제공하는 구성 메타데이터(XML 파일)로 생성된다.
- 이 메타데이터로 컨테이너는 Bean, Bean 수명주기, Bean 종속성을 만드는 방법을 알고 있다.
응용 프로그램의 객체를 지정한 후, getBean() 메서드로 해당 객체의 인스턴스에 도달함


Spring Bean Definition

관리할 Bean을 정한다.
- 주요 특성
    * class(필수): 정규화된 Java 클래스 이름
    * id: 이 Bean의 고유 식별자
    * scope: 객체의 범위(Singleton, Prototype) 
    * constructor-arg: 생성 시 생성자에게 전달해야 하는 인수
    * property: 생성 시 콩 세터에게 전달할 인수
    * 초기화(init), 파기(destroy) 메서드


XML 기반 구성 파일

<!-- A simple bean definition -->
<bean id="..." class="...">
</bean>

<!-- A bean definition with scope-->
<bean id="..." class="..." scope="singleton">
</bean>

<!-- A bean definition with property -->
<bean id="..." class="...">
	<property name="message" value="Hello World!"/>
</bean>

<!-- A bean definition with initialization method -->
<bean id="..." class="..." init-method="...“ >
</bean>

5. Spring Bean Scope

Bean Scope Description
singleton 하나의 Bean 정의가 Spring IoC Container 내에 단 하나의 객체만 존재.
prototype 하나의 Bean 정의가 다수의 객체가 존재.
request 각 HTTP request당 단일 Bean 객체가 존재. (web-aware ApplicationContext에서 유효)
session 각 HTTP session당 단일 Bean 객체가 존재. (web-aware ApplicationContext에서 유효)
global-session 각 글로벌 HTTP 세션당 단일 Bean 객체가 존재. (web-aware ApplicationContext에서 유효)

Spring Bean Scope

빈의 두 가지 종류.

- 기본적으로 명시되지 않은 모든 Bean은 Singleton이다.

1. Singleton (e.g., <bean scope=“singleton” … />)

- 스프링 Container에 'Singleton' Bean이 한 번 만들어진다.

- Singleton' Bean은 참조할 때마다 같은 Bean을 가리킨다.

- 컨테이너가 닫힐 때 수거된다.

2. Prototype (e.g., <bean scope=“prototype” … />)

- 'Prototype' Bean의 의미는 모든 Request에 대한 새로운 겍체 뜻 한다.

- 객체에 대한 참조가 없을 때 수거된다. 

Singleton

Prototype

 


예제:

PetOwner.java

package com.kwonga.spring;

public class PetOwner {
	String userName;
    
    public String getUserName() {
    	System.out.println("Person name is " + userName);
        return userName;
    }
    
    public void setUserName(String userName) {
    	this.userName = userName;
    }
    
    public AnimalType animal;
    
    public PetOwner(AnimalType animal) {
    	this.animal = animal;
    }
    
    public void play() {
    	animal.sound();
    }
 }

Singleton

animal.xml

<bean id="dog" class="com.kwonga.spring.Dog">
	<property name="myName" value="poodle" />
</bean>

<bean id="cat" class="com.kwonga.Cat">
	<property name="myName" value="bella" />
</bean>

<bean id="petOwner" class="com.kwonga.spring.PetOwner" scope="singleton">
	<constructor-arg name="animal" ref="dog" />
</bean>

MainApp.java

package com.kwonga.spring;

import org.springframework.context.ApplicationContext;

public class MainApp {
	
    public static void main(String[] args) {
    	ApplicationContext context = 
        	new ClassPathXmlApplicationContext("com/kwonga/spring/beans/bean.xml");
        
        PetOwner person1 = (PetOwner)context.getBean("petOwner");
        person1.setUserName("Alice");
        person1.getUserName();
        
        PetOwner person2 = (PetOwner)context.getBean("petOwner");
        person2.getUserName();
        
        ((ClassPathXmlApplicationContext)context).close();
    }
}


Prototype

animal.xml

<bean id="dog" class="com.kwonga.spring.Dog">
	<property name="myName" value="poodle" />
</bean>

<bean id="cat" class="com.kwonga.Cat">
	<property name="myName" value="bella" />
</bean>

<bean id="petOwner" class="com.kwonga.spring.PetOwner" scope="prototype">
	<constructor-arg name="animal" ref="dog" />
</bean>

MainApp.java

package com.kwonga.spring;

import org.springframework.context.ApplicationContext;

public class MainApp {
	
    public static void main(String[] args) {
    	ApplicationContext context = 
        	new ClassPathXmlApplicationContext("com/kwonga/spring/beans/bean.xml");
        
        PetOwner person1 = (PetOwner)context.getBean("petOwner");
        person1.setUserName("Alice");
        person1.getUserName();
        
        PetOwner person2 = (PetOwner)context.getBean("petOwner");
        person2.getUserName();
        
        ((ClassPathXmlApplicationContext)context).close();
    }
}

6. 종속성 주입 방법

1. 생성자 기반 주입
- 생성자를 통해 전달되는 전달 종속성

2. setter 기반 주입
속성 집합을 통해 전달되는 전달 종속성

 

1. 생성자 기반 주입

생성자 기반 주입법의 주의사항1

<bean id="myCollege" class="com.korea.College">
 <constructor-arg value=“500” type=“int”/>
 <constructor-arg value=“123Abc” type=“java.lang.String”/>
</bean>
public class College {
 private String collegeId;
 private int totalStudents;
 private String collegeAdd;

 public College (int totalStudents, String collegeId){
  this.totalStudents = totalStudents;
  this.collegeId = collegeId;
 }

 public College (String collegeAdd, String collegeId){
  this.collegeAdd = collegeAdd;
  this.collegeId = collegeId;
 }
}

type="int"와 type"java.lang.String" Bean에 입력해줌으로써 매개변수 전달을 확실하게 해줄 수 있다.

 

생성자 기반 주입법의 주의사항2

<bean id="myCollege" class="com.korea.College">
 <constructor-arg value=“500” type=“int” index=“0”/>
 <constructor-arg value=“123Abc” type=“java.lang.String” index=“1”/>
</bean>
public class College {
 private String collegeId;
 private int totalStudents;
 private String collegeAdd;

 public College (int totalStudents, String collegeId){
  this.totalStudents = totalStudents;
  this.collegeId = collegeId;
 }

 public College (String collegeAdd, int totalStudents){
  this.totalStudents = totalStudents;
  this. collegeAdd = collegeAdd;
 }
}

index를 지정해 매개변수 전달을 확실하게 해줄 수 있다.

 

2. Setter 기반 주입


7. Injection Collection

Tag Name Inner Tag Name Java Collection Type Specification
<list> <value> java.util.List<E> 중복 항목 허용
<map> <entry> java.util.Map<K, V> 모든 유형의 <키, 값> 쌍
<set> <value> java.util.Set<E> 중복 항목을 허용하지 않음
<props> <prop> java.util.Properties '스트링' 유형의 <키, 값> 쌍

예제:

댓글