본문 바로가기
Spring

[Spring] XML 기반 설정 의존 객체 자동 주입 (autowire)

by Amy IT 2022. 8. 17.

 

목차

     

    의존 객체 자동 주입 - autowire

    XML 기반으로 빈을 등록할 때, 의존 관계에 있는 객체를 주입하는 코드를 일일이 직접 작성해 줘야 하는 번거로움이 있었습니다. 이때, 의존 관계를 설정하고자 하는 빈에 autowire 속성을 사용하면 의존 객체를 자동으로 주입하게 되어 코드 작성이 편리해집니다. autowire 속성의 설정값으로는 다음의 네 가지가 있습니다.

     

    설정값 설명
    byName 프로퍼티의 이름과 같은 이름을 갖는 빈 객체를 자동 설정한다.
    (setter 메소드의 메소드 이름 기준)
    byType 프로퍼티의 타입과 같은 타입을 갖는 빈 객체를 자동 설정한다.
    (setter 메소드의 매개변수 타입 기준)
    constructor 생성자 파라미터 타입과 같은 타입을 갖는 빈 객체를 생성자에 자동 설정한다.
    no 자동 설정을 사용하지 않는다.

     

    autowire="byName"

    setter 메소드의 메소드 이름 기준으로 프로퍼티의 이름과 같은 이름을 갖는 빈 객체를 자동으로 주입합니다. 예시를 들어 살펴보겠습니다.

     

     

    Pencil.java

    public class Pencil {
    	private String prodName;
    	private int price;
    	public Pencil(String prodName, int price) {
    		super();
    		this.prodName = prodName;
    		this.price = price;
    	}
    	@Override
    	public String toString() {
    		return "Pencil [prodName=" + prodName + ", price=" + price + "]";
    	}
    }

     

    Desk.java

    public class Desk {
    	private double size;
    	public Desk(double size) {
    		super();
    		this.size = size;
    	}
    	@Override
    	public String toString() {
    		return "Desk [size=" + size + "]";
    	}
    }

     

    Store.java

    public class Store {
    	private String storeName;
    	private Pencil pencil;
    	private Desk desk;
    	
    	public Store() {
    		super();
    	}
    	public Store(String storeName, Pencil pencil, Desk desk) {
    		super();
    		this.storeName = storeName;
    		this.pencil = pencil;
    		this.desk = desk;
    	}
    	public String getStoreName() {
    		return storeName;
    	}
    	public void setStoreName(String storeName) {
    		this.storeName = storeName;
    	}
    	public Pencil getPencil() {
    		return pencil;
    	}
    	public void setPencil(Pencil pencil) {
    		this.pencil = pencil;
    	}
    	public Desk getDesk() {
    		return desk;
    	}
    	public void setDesk(Desk desk) {
    		this.desk = desk;
    	}
    	@Override
    	public String toString() {
    		return "Store [storeName=" + storeName + ", pencil=" + pencil + ", desk=" + desk + "]";
    	}
    }

     

    applicationContext.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">
    
    <bean id="pencil" class="com.dto.Pencil">
    	<constructor-arg name="prodName" value="A01"></constructor-arg>
    	<constructor-arg name="price" value="100"></constructor-arg>
    </bean>
    <bean id="desk" class="com.dto.Desk">
    	<constructor-arg name="size" value="30"></constructor-arg>
    </bean>
    
    <bean id="store" class="com.dto.Store" autowire="byName">
    	<property name="storeName" value="Emart"></property>
    </bean>
    
    </beans>

    주입될 빈을 등록하며 빈의 id를 주입받을 클래스의 setter 메소드의 이름과 동일하게 합니다. 여기서는 Store 클래스의 인스턴스 변수인 pencil과 desk를 설정하고자 하므로 id를 pencil과 desk로 등록합니다. 이렇게 하면 store 빈을 등록하면서 각 프로퍼티를 일일이 설정하지 않아도 프로퍼티 이름과 같은 이름을 갖는 빈 객체를 store에 자동 주입하게 됩니다. 

     

    TestMain.java

    public class TestMain {
    	public static void main(String[] args) {
    		ApplicationContext ctx = new GenericXmlApplicationContext("classpath:applicationContext.xml");
    		
    		Store store = ctx.getBean("store", Store.class);
    		System.out.println(store); 
    		//Store [storeName=Emart, pencil=Pencil [prodName=A01, price=100], desk=Desk [size=30.0]]
    	}
    }

    등록한 pencil 빈과 desk 빈이 자동으로 잘 주입되어 있는 것을 확인할 수 있습니다.

     

     

    autowire="byType"

    setter 메소드의 매개변수 타입 기준으로 프로퍼티의 타입과 같은 타입을 갖는 빈 객체를 자동으로 주입합니다. 위의 예제에서 XML 파일만 수정해 보도록 하겠습니다.

     

    applicationContext.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">
    
    <bean id="p" class="com.dto.Pencil">
    	<constructor-arg name="prodName" value="A01"></constructor-arg>
    	<constructor-arg name="price" value="100"></constructor-arg>
    </bean>
    <bean id="d" class="com.dto.Desk">
    	<constructor-arg name="size" value="30"></constructor-arg>
    </bean>
    
    <bean id="store" class="com.dto.Store" autowire="byType">
    	<property name="storeName" value="Emart"></property>
    </bean>
    
    </beans>

    빈의 id를 pencil, desk가 아닌 임의의 값으로 지정하고, store 빈의 autowire 속성값을 byType으로 설정하였습니다. setter 메소드의 매개변수 타입이 기준이 되기 때문에, 빈의 id가 프로퍼티 이름과 같지 않아도 해당하는 타입의 빈을 자동으로 주입합니다. 여기서는 Store 클래스에 Pencil 타입과 Desk 타입 빈을 자동으로 설정하여 위의 예시와 동일한 결과가 나오는 것을 확인할 수 있습니다.

     

    여러 개의 빈 중 선택하기

    이때 유의해야 할 점이 한 가지 있습니다. byType으로 자동 주입을 설정할 경우, 다음과 같이 타입이 같은 빈이 여러 개 있으면 오류가 발생한다는 점입니다. 이는 동일한 타입의 빈들 중 어떤 것을 주입해야 하는지 알 수 없기 때문입니다.

    <bean id="p" class="com.dto.Pencil">
    	<constructor-arg name="prodName" value="A01"></constructor-arg>
    	<constructor-arg name="price" value="100"></constructor-arg>
    </bean>
    <bean id="d" class="com.dto.Desk">
    	<constructor-arg name="size" value="30"></constructor-arg>
    </bean>
    <bean id="d2" class="com.dto.Desk">
    	<constructor-arg name="size" value="100"></constructor-arg>
    </bean>
    
    <bean id="store" class="com.dto.Store" autowire="byType">
    	<property name="storeName" value="Emart"></property>
    </bean>
    (에러 메시지) NoUniqueBeanDefinitionException: No qualifying bean of type 'com.dto.Desk' available: expected single matching bean but found 2: d,d2

     

    이때 여러 개의 빈 중 주입할 빈을 명시적으로 선택할 수 있는 방법이 있습니다. 

     

    (1) autowire-candidate="false"  후보에서 제외시키기

    첫 번째는 자동 주입 후보에서 제외시키는 방법입니다. 동일한 타입의 여러 빈들 중 자동 주입을 하지 않는 빈들의 속성으로 autowire-candidate="false"를 정의해 줍니다. 후보에서 제외되지 않은 해당 타입의 빈이 잘 주입된 것을 확인할 수 있습니다.

    <bean id="p" class="com.dto.Pencil">
    	<constructor-arg name="prodName" value="A01"></constructor-arg>
    	<constructor-arg name="price" value="100"></constructor-arg>
    </bean>
    <bean id="d" class="com.dto.Desk" autowire-candidate="false">
    	<constructor-arg name="size" value="30"></constructor-arg>
    </bean>
    <bean id="d2" class="com.dto.Desk">
    	<constructor-arg name="size" value="100"></constructor-arg>
    </bean>
    
    <bean id="store" class="com.dto.Store" autowire="byType">
    	<property name="storeName" value="Emart"></property>
    </bean>

     

    (2) primary="true"  후보들 중 선택하기 

    두 번째는 여러 후보들 중 사용할 빈을 명시적으로 선택하는 방법입니다. 동일한 타입의 여러 빈들 중 자동 주입을 하고자 하는 빈의 속성으로 primary="true"를 설정해 줍니다. 위의 예제와 동일한 결과가 출력됩니다.

    <bean id="p" class="com.dto.Pencil">
    	<constructor-arg name="prodName" value="A01"></constructor-arg>
    	<constructor-arg name="price" value="100"></constructor-arg>
    </bean>
    <bean id="d" class="com.dto.Desk">
    	<constructor-arg name="size" value="30"></constructor-arg>
    </bean>
    <bean id="d2" class="com.dto.Desk" primary="true">
    	<constructor-arg name="size" value="100"></constructor-arg>
    </bean>
    
    <bean id="store" class="com.dto.Store" autowire="byType">
    	<property name="storeName" value="Emart"></property>
    </bean>

     

     

    autowire="constructor"

    생성자 파라미터 타입과 같은 타입을 갖는 빈 객체를 생성자에 자동으로 주입합니다. 

     

    applicationContext.xml

    <bean id="pencil" class="com.dto.Pencil">
    	<constructor-arg name="prodName" value="A01"></constructor-arg>
    	<constructor-arg name="price" value="100"></constructor-arg>
    </bean>
    <bean id="desk" class="com.dto.Desk">
    	<constructor-arg name="size" value="30"></constructor-arg>
    </bean>
    
    <bean id="store" class="com.dto.Store" autowire="constructor">
    	<constructor-arg name="storeName" value="Emart"></constructor-arg>
    </bean>

     

    단, 생성자를 통해 자동 주입을 할 경우, 타입이 같은 빈이 여러 개 있어도 특정 빈의 id가 생성자 파라미터 이름과 동일하면 오류가 나지 않고 해당 빈으로 자동 주입을 하게 됩니다. 아래 예시에서 id가 desk인 빈이 주입된 것을 확인할 수 있습니다.

    <bean id="pencil" class="com.dto.Pencil">
    	<constructor-arg name="prodName" value="A01"></constructor-arg>
    	<constructor-arg name="price" value="100"></constructor-arg>
    </bean>
    <bean id="desk" class="com.dto.Desk">
    	<constructor-arg name="size" value="30"></constructor-arg>
    </bean>
    <bean id="d2" class="com.dto.Desk">
    	<constructor-arg name="size" value="100"></constructor-arg>
    </bean>
    
    <bean id="store" class="com.dto.Store" autowire="constructor">
    	<constructor-arg name="storeName" value="Emart"></constructor-arg>
    </bean>

     

     

    의존 객체 자동 주입 기본 설정 - default-autowire

    namespace를 설정하는 XML 파일 상단 부분에서 default-autowire 속성을 사용하여 모든 빈에 대해 공통적으로 자동 주입이 적용되도록 설정할 수 있습니다. 마찬가지로 byName, byType, constructor 설정값을 지정할 수 있습니다. 자동 주입을 기본 설정으로 하고 있기 때문에 아래 빈을 등록하는 부분에서 autowire 속성을 설정했던 코드가 빠지게 됩니다.

    <?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"
    	default-autowire="byType"
    >
    
    <bean id="pencil" class="com.dto.Pencil">
    	<constructor-arg name="prodName" value="A01"></constructor-arg>
    	<constructor-arg name="price" value="100"></constructor-arg>
    </bean>
    <bean id="desk" class="com.dto.Desk">
    	<constructor-arg name="size" value="30"></constructor-arg>
    </bean>
    
    <bean id="store" class="com.dto.Store">
    	<property name="storeName" value="Emart"></property>
    </bean>
    
    </beans>

     

     

    이상으로 XML 기반 설정으로 의존 객체를 자동 주입하는 방법을 알아보았습니다.

     

     

    참고

    https://atoz-develop.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-XML-%EC%84%A4%EC%A0%95-%ED%8C%8C%EC%9D%BC-%EC%9E%91%EC%84%B1-%EB%B0%A9%EB%B2%95-%EC%A0%95%EB%A6%AC

     

     

    댓글