Spring/DI (Dependency Injection)

DI (Dependency Injection) - 의존성 주입

p3chaeyeon 2024. 10. 2. 11:58

DI (Dependency Injection)

  • 객체가 생성될 때 필요한 의존성을 설정 파일(XML)이나 애노테이션을 통해 외부에서 주입받는 개념
  • 객체사이의 의존 관계를 자기 자신이 아닌 외부에 의해서 설정된다는 개념
  • 스프링에서는 설정파일을 사용하여 손쉽게 객체간의 의존관계를 설정하기에 스프링을 DI 컨테이너 라고 부르기도 함
  • DI 컨테이너의 역할 :  어떤 클래스가 필요로 하는 인스턴스를 자동으로 생성, 취득하여 연결
  • DI 컨테이너가 인스턴스를 생성하도록 하려면 프로그램 소스 내부에서 new 로 직접 생성하지 않고 설정파일에서 필요로 하는 클래스의 정보를 설정해 주어야한다

각 클래스간의 의존관계를 관리하기 위한 방법

  • Constructor Injection
  • Setter Injection

 

 

1. Constructor Injection

  • 생성자를 통해서 의존 관계를 연결
  • 생성자를 통해서 의존 관계를 연결하기 위해서는 XML 설정 파일에서 <bean>요소의 하위요소로 <constructor-arg>를 추가해야 한다
  • (bean)을 생성할 때 해당 객체의 생성자(constructor)에 인자를 전달하는 방식으로 값을 주입할 때 사용

 

① 전달인자가 2개 이상인 경우

public class Foo {
	public Foo(int a, String b) { }
}
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
	<constructor-arg>
		<value>25</value>
	</constructor-arg>
	<constructor-arg value="Hello" />
</bean>

 

index 속성을 이용하여 지정

<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
	<constructor-arg index="1" value="Hello" />
	<constructor-arg index="0">
		<value>25</value>
	</constructor-arg>
</bean>

 

type 속성을 이용하여 지정

<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
	<constructor-arg type="int" value="25" />
	<constructor-arg type="java.lang.String" value="Hello" /> 
</bean>

 

④ 객체를 전달할 경우에는 ref 요소를 사용

public class Foo {
	private Bar bar;
  
	public Foo(Bar bar){
	this.bar = bar;
	}
}
  
public class Bar { }
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
	<constructor-arg>
		<ref bean="bar" />
	</constructor-arg>
</bean>
  
<bean id="bar" class="Bar" />

 

 

 

2. Setter Injection

  • setter 드를 이용하여 의존 관계를 연결
  • <property>요소의 name 속성을 이용하여 값의 의존 관계를 연결시킬 대상이 되는 필드값을 지정한다

 

① 전달인자가 2개 이상인 경우

public class Foo {
	private int a
	private String b;
  
	public void setA(int a) { }
	public void setB(String b) { }
}
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
	<property name="a">
		<value>25</value>
	</property>
	<property name="b" value="Hello" />
</bean>

 

② 객체를 전달할 경우에는 ref 요소를 사용

public class Foo {
	private Bar bar;
	public void setBar(Bar bar){
	this.bar = bar;
	}
}
  
public class Bar { }
<!-- applicationContext.xml -->
<bean id="foo" class="Foo">
	<property name="bar" ref="bar"></property>
</bean>
  
<bean id="bar" class="Bar" />

 

 

 

 

bean 생성 방법

  1. <bean> 태그
  2. 클래스 위 @Component 어노테이션 사용
  3. 메서드 위 @Bean 어노테이션 사용

 

1. <bean> 태그

  • applicationContext.xml
<bean id="messageBeanImpl" class="sample01.MessageBeanImpl" >
	<constructor-arg>
		<value>사과</value>
	</constructor-arg>
	
	<!-- messageBeanImpl.setCost(5000); -->
	<!-- SetCost(int cost) 에서 앞, 뒤 빼고 소문자로 작성 -->
	<property name="cost">
		<value>5000</value>
	</property>
	
	<!-- messageBeanImpl.setQty(3); -->
	<!-- SetQty(int qty) 에서 앞, 뒤 빼고 소문자로 작성 -->
	<property name="qty">
		<value>3</value>
	</property>	
</bean>

 

 

2. 클래스 위 @Component 어노테이션 사용

  • applicationiContext.xml
<context:component-scan base-package="sample01"></context:component-scan>

// " 패키지에서 어노테이션으로 빈을 설정한다"

// 설정은 아님. 설정을 위해 어노테이션 쓰겠다

 

  • 인터페이스 구현 java 파일
@Component // 스프링에서 **빈(Bean)**으로 관리할 클래스
@Value // 속성 주입 (값 주입)
@Autowired // 자동 의존성 주입
@Component @ComponentScan 을 사용하면 특정 패키지에서 @Component 가 붙은 클래스를 자동으로 스캔하고 빈으로 등록
  • @Service: 비즈니스 로직을 처리하는 서비스 클래스에 사용
  • @Repository: 데이터 접근 객체(DAO) 클래스에 사용
  • @Controller: MVC 패턴에서 컨트롤러 클래스에 사용
@Value 주입할 수 있는 값:
  • 기본값
  • 설정 파일(application.properties, application.yml)에서 정의된 값
  • 시스템 환경 변수
@Autowired 주입 방식:
  1. 생성자 주입: 권장되는 방식이며, 객체가 생성될 때 의존성을 함께 주입
  2. 세터 주입: 세터 메서드를 통해 의존성을 주입하는 방식
  3. 필드 주입: 직접 필드에 주입하는 방식입니다. 하지만 테스트하기 어렵고 캡슐화를 위반할 수 있기 때문에 권장되지 않음

 

 

 

3. 메서드 위 @Bean 어노테이션 사용

  • applicationiContext.xml
<context:component-scan base-package="spring.conf"></context:component-scan>

 

  • SpringConfiguration.java
@Configuration // 나는 일반 자바파일이 아니다; 스프링 설정파일 취급
public class SpringConfiguration {
	@Bean // 함수로 설정
	public MessageBeanImpl messageBeanImpl() {
		return new MessageBeanImpl("사과");
	}
}
	
/** return 을 받는 함수는 앞에 get이 붙는 규칙 따를 때 */
@Configuration // 나는 일반 자바파일이 아니다; 스프링 설정파일 취급
public class SpringConfiguration {
	@Bean(name="MessageBeanImpl")
	public MessageBeanImpl getMessageBeanImpl() {
		return new MessageBeanImpl("사과");
	}
	
	MessageBeanImpl getMessageBeanImpl = new MessageBeanImpl("사과");
}

 

 

 

 ⚒️ 예제

 

Chapter02_XML

  Java applicationContext.xml
sample01 // MessageBeanImpl 인스턴스 생성 (생성자 주입)
MessageBeanImpl messageBeanImpl = new MessageBeanImpl("사과");
 
// setter 메서드로 필드 값 설정
messageBeanImpl.setCost(5000);
messageBeanImpl.setQty(3);
bean id="messageBeanImpl" class="sample01.MessageBeanImpl" >
<constructor-arg>
<value>사과</value>
</constructor-arg>
 
<!-- messageBeanImpl.setCost(5000); -->
<!-- SetCost(int cost) 에서 앞, 뒤 빼고 소문자로 작성 -->
<property name="cost">
<value>5000</value>
</property>
 
<!-- messageBeanImpl.setQty(3); -->
<!-- SetQty(int qty) 에서 앞, 뒤 빼고 소문자로 작성 -->
<property name="qty">
<value>3</value>
</property>        
</bean>
sample02 // CalcAdd 인스턴스 생성 (생성자 주입)
CalcAdd calcAdd = new CalcAdd(25, 36);
 
 
// CalcMul 인스턴스 생성 (기본 생성자)
CalcMul calcMul = new CalcMul();
 
// setter 메서드로 필드 값 설정
calcMul.setX(25);
calcMul.setY(36);
<!-- 생성자 주입(Constructor Injection)을 사용하는 CalcAdd bean 정의 -->
<bean id="calcAdd" class="sample02.CalcAdd">
    <constructor-arg value="25" />
    <constructor-arg value="36" />
</bean>
 
<!-- 세터 주입(Setter Injection)을 사용하는 CalcMul bean 정의 -->
<bean id="calcMul" class="sample02.CalcMul">
    <property name="x" value="25" />
    <property name="y" value="36" />
</bean>
sample03 // SungJukImpl 인스턴스를 생성
SungJukImpl sungJukImpl = new SungJukImpl();
<!-- SungJukDTO: Setter Injection -->
<bean>
    <property name="name" value="홍길동"/>
    <property name="kor" value="97"/>
    <property name="eng" value="100"/>
    <property name="math" value="95"/>
</bean>
 
<!-- SungJukImpl: Constructor Injection -->
<bean id="sungJuk" class="sample03.SungJukImpl">
    <constructor-arg ref="sungJukDTO"/>
</bean>        

 

sample01

// D:\Spring\work
Chapter02_XML/sample01 XML bean 생성
Chapter02_ANNO/sample01 @Component Annotation bean 생성
Chapter02_ANNO_Bean/sample01 @Bean Annotation bean 생성

 

sample02

// D:\Spring\work
Chapter02_XML/sample02 XML bean 생성
Chapter02_ANNO/sample02 @Component Annotation bean 생성
Chapter02_ANNO_Bean/sample02 @ Bean Annotation bean 생성

 

sample03

// D:\Spring\work
Chapter02_XML/sample03 XML bean 생성
Chapter02_ANNO/sample03 @Component Annotation bean 생성
Chapter02_ANNO_Bean/sample03 @ Bean Annotation bean 생성

 

sample04

// D:\Spring\work
Chapter02_XML/sample04 XML bean 생성
Chapter02_ANNO/sample04 Annotation bean 생성
Chapter02_ANNO_Bean/sample04 @ Bean Annotation bean 생성

 

sampe05

// D:\Spring\wor
Chapter02_XML/sample05 XML bean 생성