본문 바로가기
Spring/이론

의존성 주입(Dependency Injection)

by 모스키토끼 2020. 3. 5.

객체 의존성

public class PetOwner{
    private AnimalType animal;

    public PetOwner() {
    	this.animal = new Dog();
    }    
}
  • PetOwner 객체는 AnimalType 객체 (이 경우 Dog)에 의존
  • PetOwner 객체는 AnimalType 객체의 생성을 제어
  • PetOwner와 AnimalType 객체 사이가 연결됨
  • AnimalType 객체를 변경하면 PetOwner 객체가 변경

PetOwner와 Dog는 강하게 결합이 되어있다  = tight coupling
-> 다른 경우를 적용하려면 소스코드를 바꿔야 하는 상황
(만약 Cat을 animal에 넣으려고 하면 PetOwner 코드를 바꿔줘야 한다. -> 다른 상황마다 코드를 바꿔야되는 상황)
ㄴ 해결하기 위해 나온 것이 Dependency Injection

 

의존성 주입이란?

  • Bean Container가 설정 파일을 보고 적절한 bean(객체) 생성
    ㄴ Spring에서 제공
    ex) Bean A ->(Bean Container) 의존성 주입, Bean 생성 -> Bean B 짜잔
  • Container가 생성자에 무엇을 주입하냐에 따라서 값이 달라진다.
    예시)
public class PetOwner{
    private AnimalType animal;

    public PetOwner(AnimalType animal) {
    	this.animal = animal;
    }    
}

public class Dog 
	implements AnimalType{
    //…
}
public class Cat 
	implements AnimalType{
    //…
}
  • 객체가 아닌 framework가 객체의 종속성을 주입하는 디자인 패턴
  • framework에 의해 동적으로 주입되므로 객체간 결합이 줄어든다.

Spring Container

  • 스프링 프레임워크의 핵심요소
  • 빈을 포함하고 관리하는 역할
    • 빈 생성(Object)
    • 빈들을 연결
    • 연결 설정
    • 빈들의 완전한 라이프사이클을 관리
  • 설정 방법 3가지
    • XML
    • Java annotations
    • Java-based Configuration
  • Spring은 2가지 컨테이너를 제공
    • BeanFactory
      - DI(Dependency injection)를 주로 사용한 가장 간단한 factory
      - 자원이 제한적일 때 사용( mobile, applets 등)
      - XMLBeanFactory: 가장 보편적으로 사용되는 implementation
    • ApplicationContext
      - 좀 더 복잡한 factory
      - 요청으로 빈을 연결하고 끊는다.
      - Publish application events to listeners
      - Enterprise aware functions
      - ClassPathXmlApplicationContext: 가장 보편적으로 사용되는 implementation
      ex)
      ApplicationContext context =
       new ClassPathXmlApplicationContext("kr/ac/hansung/spring/beans/bean.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");

DI 예시

//DI를 받을 인터페이스
public interface AnimalType{
	public void sound();
}
// Bean으로 등록 될 클래스들
public class Cat implements AnimalType{
	String myName;
    
    public void setMyName(String name){
    	this.myName = name;
    }
    public void sound() {
    	sysout("Cat name =" + myName + ": "+ "Meow!");
    }
}

public class Dog implements AnimalType{
	String myName;
    
    public void setMyName(String name){
    	this.myName = name;
    }
    public void sound() {
    	sysout("Dog name =" + myName + ": "+ "Bow wow!");
    }
}
public class PetOwner{
	public AnimalType animal;
    
    public PetOwner(AnimalType animal){
    	this.animal = animal;
    }
    public void play() {
    	animal.sound();
    }
}


//Configure beans and dependencies
// animal.xml
...

//빈 정의
<bean id="dog" class = "package 명.Dog">
	<Property name = "myName" value = "poodle"></property>
</bean>

<bean id="cat" class = "package 명.Cat">
	<Property name = "myName" value = "bella"></property>
</bean>

//DI 부분
<bean id="petOwner" class = "package 명.PetOwner">
	<constructor-arg ref = "cat" </constructor -arg> // dog로 바꿔도 java 소스에 영향 없음
</bean>
//main
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("xml 위치/animal.xml");

PetOwner person = (PetOwner) context.getBean("petOwner");
person.play();
context.close();

Spring Bean Scope

  • singleton (Default): 모든 getBean() 호출을 단일 빈 객체가 담당
  • prototype: 모든 getBean() 호출을 새로운 객체가 담당
  • request: 한 HTTP request 당 단일 빈 객체가 담당
  • session: 한 HTTP session 당 단일 빈 객체가 담당
  • global-session: 한 global HTTP session 당 단일 빈 객체가 담당

예시)

public class PetOwner{
	String userName;
    
    public String getUserName(){
    	sysout("Person name is " + userName);
        return userName;
    }
    
    public void setUserName(String userName){
    	this.userName = userName;
   	}
    
    public AnumalType animal;
    
    public PetOwner(AnimalType anumal){
    	this.animal = animal;
    }
    
    public void play() {
    	animal.sound();
    }
}
PetWoner person1 = (PetOwner) context.getBean("PetOwner");
person1.setUserName("Alice");
person1.getUserName();

PetOwner person2 = (PetOwner) context.getBean("PetOwner");
person2.getUserName();

// 결과
Person name is Alice
Person name is Alice

만약 xml 설정에서 perOwner의 scope 값을 prototype으로 설정하면
두번 째 출력값에 Alice 대신 null이 들어온다.//userName 값이 초기화 되지 않았기 때문

 

Dependency Injection Methods

  • Contructor-based Injection
     - 생성자를 통해 종속성을 전달
  • Setter-based Injection
     - setters 속성을 통해 종속성을 전달

Contructor-based Injection (모호성 존재)

기본 예시)

<bean id="petOwner" class="kr.ac.hansung.spring.PetOwner" >
    <constructor-arg    ref ="dog" />
</bean>

public class PetOwner {

    public AnimalType animal;

    public PetOwner(AnimalType animal) {
	this.animal = animal;
    }
    …
}

 

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;
 }
}

2. 타입이 전부 존재하는 경우 -> 뒤에 index를 명시해서 순서를 나타낸다.

예시)

<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;
 }
}

Setter-based Injection

- Setter 메서드를 호출하는 설정(constructor-arg 대신 property 사용)

예시)

<bean id="petOwner" class="kr.ac.hansung.spring.PetOwner">
    <property name="animal" ref="dog" />
</bean>

public class PetOwner {

    public AnimalType animal;

    public void setAnimal(AnimalType animal) {
	this.animal = animal;
    }

    …
}

 

Spring Annotation

- xml 설정 대신 annotation을 사용하여 간단하게 설정을 할 수도 있다.

  • @Required
    - 요구 사항 체크를 할 수 있다.
public class Boy {
 private String name;
 private int age;
   
 @Required
 public void setName(String name){
  this.name = name;
 }
   
 @Required
 public void setAge(int age){
  this.age = age;
 }
   
 //   getters ...
}

<bean id=“boy” class=“Boy”>
 <property name=“name” value=“Rony”/>
 <property name=“age” value=“10”/>
</bean>

//만약 밑에 코드처럼 age를 빼먹는 다면 age속성이 요구된다는 메세지가 뜬다.
<bean id=“boy” class=“Boy”>
 <property name=“name” value=“Rony”/>
</bean>
  • @Autowired
    - 의존성 주입을 xml 설정 대신 annotation을 다는 것만으로 설정할 수 있다.
public class Boy {
 private String name;
 private int age;
   
 //   getters and setters ...
}

public class College {
 
 /* Autowired를 사용하면 지워도 되는 부분
 private Boy student; 
 
 public void setStudent(Boy aboy){
  this.stuendt = aboy;
  */
  
  @Autowired
  private Boy student;
 }

 
}


<bean id=“boy” class=“Boy”>
 <property name=“name” value=“Rony”/>
 <property name=“age” value=“10”/>
</bean>

<bean id=“college” class=“College”>
  /* Autowired를 사용하면 지워도 되는 부분
  	<property name=“student” ref=“boy”/>
  */
</bean>
  • @Qualifier
    - @Autowired를 사용했을 때 타입 모호성을 해결할 수 있다.
public class Boy {
 private String name;
 private int age;
   
 //   getters and setters ...
}


public class College {
 
@Autowired
@Qualifier(value=“tony”)
 private Boy student; 
 
  //   getters ...
}

<bean id=“boy1” class=“Boy”>
 <qualifier value=“rony”/>
 <property name=“name” value=“Rony”/>
 <property name=“age” value=“10”/>
</bean>

<bean id=“boy2” class=“Boy”>
 <qualifier value=“tony”/>
 <property name=“name” value=“Tony”/>
 <property name=“age” value=“8”/>
</bean>

<bean id=“college” class=“College”> 
</bean>
  • @Resource
    - @Autowired와 같은 역할을 하지만 Autowired는 타입을 체크하여 주입하고 Resource는 이름(bean id)을 체크하여 주입한다.
<bean id=“boy1” class=“Boy”>
 <property name=“name” value=“Rony”/>
 <property name=“age” value=“10”/>
</bean>

<bean id=“boy2” class=“Boy”>
 <property name=“name” value=“Tony”/>
 <property name=“age” value=“8”/>
</bean>

<bean id=“college” class=“College”>
</bean>

public class College {
  
  @Resource(name=“boy1”)
  private Boy student; 
 
  //   getters and setters ...
}

'Spring > 이론' 카테고리의 다른 글

DB 연동(with Spring JDBC)  (0) 2020.03.09
관점 지향 프로그래밍(AOP, Aspect Oriented Programming)  (0) 2020.03.07
JSP(Java Server Pages)  (0) 2020.03.05
Servlet  (0) 2020.03.04
Spring Framework 개요  (0) 2020.03.04

댓글