[Spring] Bean Annotation

Bean 객체를 만들 때, Configuration.java 또는 bean.xml 파일이 아닌 Annotation을 이용해 객체 소스파일에서 Bean 설정을 완료하는 방식이다. 이로써 빈 객체를 등록하는 과정을 클래스를 작성하는 과정에 동시에 수행할 수 있다. Spring 핵심은 IoC 컨테이너에 빈을 생성하고 이들을 주입하는 방법이 점차 쉬운 방법으로 발전했다는 것이다.

어노테이션을 사용하기 위해 beans.xml 상단에 context 네임스페이스를 추가한다. 그리고 <context:annotaion-config> 태그를 통해 bean 객체 클래스에 설정된 어노테이션을 사용할 수 있도록 명시한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/context
						http://www.springframework.org/schema/context/spring-context.xsd">
						
	<!-- bean 클래스에 설정되어 있는 어노테이션을 이용함 -->
	<context:annotation-config/>
	
</beans>

@Required

@Required 어노테이션은 빈 객체 내부에 필수적으로 주입되어야 할 변수를 다룬다. 그러나 @Required는 Spring 5.1 이상부터는 아무런 일도 하지 않는다. 5.1 이상 버전에서는 deprecated 되는 것을 확인할 수 있으며 빈 객체는 생성자에서 모든 값을 주입받도록 권장한다. 결론적으로 5.1 버전부터는 아무일도 하지 않는다.

@Autowired

@Autowired 어노테이션은 클래스 타입을 통한 자동 주입을 지원한다. Bean 객체의 Setter 위에 @Autowired 를 지정한다. Setter 로 주입할 수 있는 객체 타입을 IoC 컨테이너에서 찾아 자동으로 주입한다. 아래와 같이 객체를 설계하는 과정에서 어노테이션을 부여해 간단하게 설정할 수 있다.

public class TestBean1 {
	private int data1;
	private DataBean1 data2;
	
	public int getData1() {
		return data1;
	}

	public DataBean1 getData2() {
		return data2;
	}
	
	@Autowired
	public void setData2(DataBean1 data2) {
		this.data2 = data2;
	}

	public void setData1(int data1) {
		this.data1 = data1;
	}
}

더 편리한 점은 @Autowired 어노테이션을 변수 위에 선언하는 것만으로도 Setter 메서드 주입을 대체할 수 있다는 것이다. 아래 코드 역시 동일하게 동작하는 것을 확인할 수 있다. 참고로, 주입할 빈이 IoC 컨테이너에 존재하지 않을 때, 오류를 발생시키지 않는 방법이 있다. 원하는 빈 객체가 존재하지 않아 초기값 그대로 전달하기 위해서는 @Autowired(required=false) 어노테이션을 선언한다.

package com.springpractice.beans;

import org.springframework.beans.factory.annotation.Autowired;

public class TestBean1 {
	private int data1;
	@Autowired
	private DataBean1 data2;
	
	public int getData1() {
		return data1;
	}

	public DataBean1 getData2() {
		return data2;
	}

	public void setData1(int data1) {
		this.data1 = data1;
	}
}

@Qualifier

@Qualifier 어노테이션은 자동 주입할 Bean 객체가 여러 개 존재하는 경우 사용한다. byName 옵션과 비슷하다고 느끼면 될 것 같다. 예를 들어서 DataBean1 타입 빈이 IoC 컨테이너에 여러 개 등록되어 있을 때, id를 통한 주입처럼 식별자에 따라 주입할 빈을 달리한다. 아래는 앞서 설명한 경우를 설명하는 경우다. 현재 IoC 컨테이너에 다음과 같은 빈 객체들이 등록된 경우를 생각해보자.

// BeanConfigClass.java
package com.springpractice.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.springpractice.beans.DataBean1;
import com.springpractice.beans.TestBean1;

@Configuration
public class BeanConfigClass {
	
	@Bean(name="tb1")
	public TestBean1 bean1() {
		return new TestBean1();
	}
	
	@Bean(name="obj1")
	public DataBean1 dbean1() {
		return new DataBean1();
	}
	
	@Bean(name="obj2")
	public DataBean1 dbean2() {
		return new DataBean1();
	}
}

DataBean1 타입 클래스가 2개 등록된 상태에서 TestBean1 빈 객체에 둘 중 하나를 주입하려고 한다. 이 때, @Qulifier를 사용해 개발자가 원하는 빈을 식별해 값을 주입할 수 있다.

package com.springpractice.beans;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class TestBean1 {
	private int data1;
	@Autowired
	@Qualifier("obj1")
	private DataBean1 data2;
	
	public int getData1() {
		return data1;
	}

	public DataBean1 getData2() {
		return data2;
	}

	public void setData1(int data1) {
		this.data1 = data1;
	}
}

생성자 주입

생성자에 주입 시 참조변수 타입 변수들은 자동으로 바인딩되어 주입된다. 그러나 기본 자료형 및 문자열 값들은 직접 주입 값을 설정해야하는데, 이 때 @Value 어노테이션을 사용한다. 아래는 해당 어노테이션이 사용되는 예시다. 그런데 이렇게 동작시켜보면 주입이 되질 않는다. 들어보니까 생성자를 통해 주입하는 방법은 Component를 사용할 때 더 배울 수 있다고 한다.

package com.springpractice.beans;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;

public class TestBean2 {
	private int data1;
	@Autowired
	@Qualifier("obj1")
	private DataBean1 data2;
	
	public TestBean2() {}
	
	public TestBean2(@Value("100") int data1, DataBean1 data2){
		this.data1 = data1;
		this.data2 = data2;
	}

	public int getData1() {
		return data1;
	}

	public void setData1(int data1) {
		this.data1 = data1;
	}

	public DataBean1 getData2() {
		return data2;
	}

	public void setData2(DataBean1 data2) {
		this.data2 = data2;
	}	
}

Updated:

Leave a comment