Spring IoC - Dependency Injection

dev_joo·2025년 8월 21일

Spring 노트 필기

목록 보기
5/10

IoC

객체 생성과 의존 관계를 컨테이너가 자동으로 관리하는 핵심 원리
스프링은 제어의 역행을 Dependency Lookup, Dependency Injection 두 가지 형태로 지원한다.

Dependency Loockup

컨테이너가 운용에 필요한 객체를 생성하면 클라이언트가 스스로 필요한 의존 객체를 검색하여 사용하는 방식

Dependency Injection (DI)

객체 사이의 의존관계를 코드에서 직접 생성하지 않고, 스프링 설정파일에 등록된 정보 또는 어노테이션을 바탕으로 컨테이너가 자동으로 처리하는 것. (외부에서 의존성을 주입하는 설계 패턴)
Constructor Injection, Setter Injection 두 가지 방식으로 구현된다.
(Spring 컨테이너가 객체 생성과 의존성 주입을 대신 수행)

1. Constructor Injection 방식

의존 관계에 있는 객체에 대한 객체 생성 코드를 직접 코드에 명시하지 않고 컨테이너가 구동될 때,
등록된 매개변수를 가지는 생성자를 호출하여 생성자의 매개변수로 의존관계에 있는 객체의 주소 정보를 전달하는 것

class Whole {
	private Part part;
    
    public Whole(Part part){
    	this.part = part;
    }
}

스프링 설정파일의 bean 요소에 constructor-arg 요소를 추가해 ref 속성에 생성자의 매개변수로 전달될 bean 객체를 지정해준다.

<!--applicationContext.xml-->
... 생략
<bean id="ContainerBean" class="com.spring.biz.Whole">
  <constructor-arg ref="containedBean"/>
</bean>
<bean id="containedBean" class="com.spring.biz.Part"/>

Constructor Injection에서 컨테이너의 클래스 생성 순서

스프링 컨테이너는 기본적으로 등록된 bean 순서대로 객체를 생성하며, 기본 생성자 호출을 원칙으로 하지만, 생성자 주입으로 매개변수를 받아들이는 객체의 생성자가 먼저 실행되어 매개변수로 들어가는 객체가 먼저 생성된다.

Spring Constructor Injection 으로 연결된 Bean 관계 = Aggregation

각 Bean은 컨테이너가 독립적으로 관리
Whole이 없어져도 Part는 살아남을 수 있음
객체 생성 책임이 포함하는 클래스가 아니라 컨테이너에게 있음

일반적인 singleton Bean DI 상황에서는 Aggregation 관계
(특정 Bean이 prototype scope 이고 다른 Bean 안에서만 쓰이도록 강하게 결합시키면 “Composition처럼” 동작)


2. Setter Injection 방식

Setter 메소드를 호출하여 의존성 주입을 처리하는 방법으로, Setter 메소드를 스프링 컨테이너가 자동으로 호출하며, 호출 시점은 <bean> 객체 생성 직후이다. 그래서 Setter Injection을 사용할 땐 기본 생성자가 필요하다.

class Obj {
	private Element element;
    private int value;
    
    public void setElement(Element ele){
    	this.element = ele;
    }
    public void setValue(int val){
    	this.vlaue = val;
    }
}

스프링 설정파일의 <bean> 요소에 <property> 요소를 추가해 name 속성에 setter 메소드를 지정해주고 (ex: setElement()의 경우 name="element"와 같은 규칙) setter 메소드에 매개변수로 전달되는 <bean>객체는 ref 속성에, 기본타입의 값은 value 속성에 지정해준다.

<!--applicationContext.xml-->
... 생략
<bean id="obj" class="com.spring.biz.Obj">
  <property name="element" ref="ele"/>
  <property name="value" value="2000"/>
</bean>

<bean id="ele" class="com.spring.biz.Element"/>

p 네임스페이스를 사용해 간단하게 Setter Inject

스프링 설정파일의 루트 엘리먼트 <beans>에 p네임스페이스를 선언하면 <bean>요소에 <property> 요소를 추가하지 않고도 네임스페이스를 활용해 Setter Injection을 할 수 있다.

<!--applicationContext.xml-->
<beans xmlns="~~~~"
       ...생략
       xmlns:p="http://www.springframework.org/schema/p"
       ...
       >
  <bean id="obj" class="com.spring.biz.Obj"
        p:element-ref="ele" p:value="2000"/>
   <bean id="ele" class="com.spring.biz.Element"/>
</beans>

Collection 객체의 의존성 주입

스프링은 List와 같은 java의 Collection 객체를 의존성 주입하기 위한 엘리먼트를 지원한다.

컬렉션 유형엘리먼트
java.utill.List<list>
java.util.Set<set>
java.util.Map<map>
java.util.Properties<props>

p 네임스페이스를 활용할 땐 컬렉션 매핑 엘리먼트를 사용할 수 없다.

대신 컬렉션을 별도 빈으로 정의하고 util 네임스페이스를 활용하면 , 그 빈을 p 네임스페이스로 참조할 수 있다.

1) 컬렉션을 별도의 <bean>으로 정의:

<util:list id="stringList">
    <value>Apple</value>
    <value>Banana</value>
</util:list>

<bean id="collectionBean" class="com.example.CollectionBean" 
      p:list-ref="stringList"/>

2) utill 네임스페이스 :

xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util.xsd"

Collection 객체 의존성 주입 예

    <bean id="collectionBean" class="com.example.CollectionBean">
        <property name="list">
            <list>
                <value>Apple</value>
                <value>Banana</value>
                <value>Cherry</value>
            </list>
        </property>

        <property name="set">
            <set>
                <value>10</value>
                <value>20</value>
                <value>30</value>
            </set>
        </property>

        <property name="map">
            <map>
                <entry key="one" value="1"/>
                <entry key="two" value="2"/>
            </map>
        </property>

        <property name="props">
            <props>
                <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql://localhost:3306/test</prop>
            </props>
        </property>
    </bean>
</beans>

컴포넌트 스캐닝 및 Bean 등록

Spring은 컨테이너에 등록된 Bean을 대상으로만 의존성 주입(DI)을 수행한다.

1. Annotation 기반

@Component 컴포넌트 스캔 설정

스프링 설정파일에 <context:componenet-scan> 엘리먼트를 정의해 추가하면 base-package 속성에 따라 해당 패키지 경로에 있는 클래스들을 스캔해 @Component 어노테이션이 작성되어있다면 자동으로 bean을 등록해 컨테이너가 객체를 생성해준다.

<beans ...생략
       ...
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="...생략...
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.2.xsd">
  
</beans>

<context:component-scan base-package="com.spring.biz"></context:component-scan>

@Component 어노테이션은 각각 @Component를 상속받은 @Sevice, @Repository, @Controller 어노테이션으로 대체될 수 있으며 이 세 가지 어노테이션은 해당 클래스의 MVC 아키텍처 구성 요소의 역할을 명시하고 역할에 맞는 추가적인 기능을 제공한다.

@Component

다음 네 가지 코드는 모두 똑같이 aclass라는 이름의 bean객체로 등록된다.

<bean id="aclass" class="com.spring.biz.Aclass"/>
@Component("aclass")
public class Aclass {}
스프링 클래스가 id나 name 속성을 지정하지 않았다면 클래스 이름의 첫 글자를 소문자로 변경한 이름으로 자동 설정해준다.
<bean class="com.spirng.biz.Aclass"/>
@Component
public class Aclass {}

@Autowired

org.springframework.beans.factory.annotation.Autowired
주로 변수 위에 설정되어 해당 타입의 객체를 찾아서 자동으로 할당해준다.
(변수의 타입을 기준으로 의존성 주입)
컨테이너로부터 주입받을 객체임을 명시한다.

@Qualifier

org.springramewoerk.beans.factory.annotation.Qualifier
다형성 구현 등의 이유로 같은 타입의 객체가 모두 메모리에 생성된 경우 어떤 객체를 의존성 주입할지 판단하기 위해 Autowired어노테이션이 작성된 (멤버변수)객체에 주입받을 객체의 이름 정보를 추가해 이름을 기준으로 의존성 주입
컨테이너에게 어떤 클래스로 주입받을지 알려준다.

@Resource

javax.annotation.Resource
@Autowired + @Qualifier
name 속성을 사용할 수 있어서 @Qualifier처럼 컨테이너가 해당 이름으로 생성된 객체를 검색해 의존성 주입
컨테이너로부터 어떤 클래스로 주입받을지 명시한다.

@Inject

javax.annotation.Inject
Resource와 같이 이름을 기반으로 의존성 주입


2. Annotation 방식과 XML 설정 방식을 병행하기

XML 설정 방식

장점 : java 소스코드 수정하지 않고 객체를 교체할 수 있어 유지보수가 편리해진다.
단점 : XML 설정을 작성하는것이 복잡하고 어느 객체가 주입받는 객체이고 주입되는 객체인지(의존관계) 소스코드에 명시되어있지 않아 XML 파일을 해석해야한다.

Annotation 방식

장점 : XML 설정의 부담이 없고 의존관계가 명시되어있다.
단점 : 의존관계가 명시되어있어 객체 교체 시 자바소스코드의 수정이 필요하다.

XML 설정방식 + Annotation

주입받는 클래스 정의 부분에서는 컨테이너로부터 주입받을 객체임을 명시하는 @Autowired를 작성해 bean 등록과 객체 생성을 자동화하고

주입되는 객체의 클래스 정의부분에 @Component를 작성하지 않고 XML에서 직접 bean 등록을 해 주입될 객체만 bean에 등록시켜 자동으로 컨테이너가 생성하도록 한다.

변경되지 않는 객체는 어노테이션으로 작성하고, 변경될 가능성이 있는 객체는 XML 설정을 사용한다.

이렇게 하면 객체를 교체할 때는 자바코드 수정 없이 XML 수정만으로 객체를 교체할 수 있게 된다.

profile
풀스택 연습생. 끈기있는 삽질로 무대에서 화려하게 데뷔할 예정 ❤️🔥

0개의 댓글