[Spring] 의존객체 자동 주입(Automatic Dependency Injection), @Autowired, @Resource, @Inject
| 의존객체 자동 주입(Automatic Dependency Injection)
의존 객체 자동 주입(Automatic Dependency Injection)은 스프링 설정파일에서 <constructor-arg> 혹은 <property> 태그로 의존 객체 대상을 명시하지 않아도 스프링 컨테이너가 자동적으로 의존 대상 객체를 찾아 해당 객체에 필요한 의존성을 주입하는 것을 말한다.
이것을 구현하는 방법은 @Autowired 또는 @Resource 어노테이션을 사용하여 구현한다. 그리고 이 두 어노테이션은 의존 객체를 찾는 방식에 있어 차이가 있다.
@Autowired는 주입하려고 하는 객체의 타입이 일치하는지를 찾고 객체를 자동으로 주입한다. 만약에 타입이 존재하지 않는다면 @Autowired에 위치한 속성명이 일치하는 bean을 컨테이너에서 찾는다. 그리고 이름이 없을 경우 나중에 포스팅할 @Qualifier 어노테이션의 유무를 찾아 그 어노테이션이 붙은 속성에 의존성을 주입한다.
타입 => 이름 => Qualifier => Fail
반면에 @Resource는 이름을 기준으로 객체를 찾는다. 만일 이름이 존재하지 않는다면 타입을 기준으로 자동적으로 객체를 찾아 주입한다. 마지막으로 @Qualifier 어노테이션의 유무를 판별한 후 그 어노테이션이 붙은 속성을 주입한다.
이름 => 타입 => Qualifier => Fail
@Inject는 @Autowired와 동일하게 작동한다. 하지만 자동주입될 bean 객체를 찾을 때 그 찾는 순서가 다르다.
타입 => Qualifier => 이름 => Fail
<프로젝트 구조>
| @Autowired
@Autowired는 스프링에서 제공하는 어노테이션이다. @Autowired는 다음과 같이 쓰일 수 있다. <context:annotation-config/> 구문을 꼭 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"
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-3.2.xsd">
<context:annotation-config/>
<bean id="gun" class="com.tutorial.spring.Gun"/>
<bean id="gunPlayer" class="com.tutorial.spring.Player">
</bean>
</beans>
@Autowired는 속성, 새터 그리고 생성자 모두에 어노테이션을 붙일 수 있다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Player {
// 속성값에 붙일 수 있다
@Autowired
private Weapon weapon;
Player(){
}
//@Autowired 생성자에도 붙일 수 있다
public Player(Weapon weapon) {
super();
this.weapon = weapon;
}
//@Autowired 새터에도 붙일 수 있다
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public Weapon getWeapon() {
return weapon;
}
public void usePlayerWeapon() {
weapon.useWeapon();
}
}
public class Main {
public static void main(String[] args) {
String xmlConfigPath = "classpath:appContext.xml";
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(xmlConfigPath);
Player gunPlayer1 = ctx.getBean("gunPlayer", Player.class);
gunPlayer1.usePlayerWeapon();
}
}
// 결과
Use Gun
| @Resource
@Resource는 bean의 id속성을 기준으로 프로퍼티의 이름을 찾아서 의존성을 주입한다. 역시 <context:annotation-config/> 구문을 꼭 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"
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-3.2.xsd">
<context:annotation-config/>
<bean id="weapon" class="com.tutorial.spring.Gun"/>
<bean id="gunPlayer2" class="com.tutorial.spring.Player2">
</bean>
</beans>
@Resource 는 생성자를 제외한 새터 및 속성값에 어노테이션을 붙일 수있다. 위 xml에서 명시한 weapon id를 기준으로 속성명이 weapon인 속성을 찾는다.
import org.springframework.context.support.GenericXmlApplicationContext;
import javax.annotation.Resource;
public class Player2 {
// 속성값에 붙일 수 있다
@Resource
private Weapon weapon;
Player2(){
}
// 생성자에는 불가
public Player2(Weapon weapon) {
super();
this.weapon = weapon;
}
//@Resource 새터에도 붙일 수 있다
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public Weapon getWeapon() {
return weapon;
}
public void usePlayerWeapon() {
weapon.useWeapon();
}
}
public class Main {
public static void main(String[] args) {
String xmlConfigPath = "classpath:appContext.xml";
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(xmlConfigPath);
Player2 gunPlayer = ctx.getBean("gunPlayer2", Player2.class);
gunPlayer.usePlayerWeapon();
}
}
// 결과
Use Gun
| @Inject
@Inject는 @Autowired와 흡사하다. 다만 자동 주입할 bean객체를 찾는 순서가 다를 뿐이다. 실무에서는 @Qualifier 어노테이션을 통해 명시적으로 어느 bean객체를 어느 속성에다 주입할 것인지를 명시하는 것이 올바른 코딩법이기 때문에 이것 순서까지 고려해서 자동 주입할 필요는 없을 것 같다. 다만 이 순서의 차이는 알고 있으면 좋다고 생각한다.
@Inject를 사용하기 위해서는 maven이나 gradle에 javax 라이브러리 의존성을 추가해야한다.
pom.xml
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
appContext.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"
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-3.2.xsd">
<context:annotation-config/>
<bean id="weapon" class="com.tutorial.spring.Gun"/>
<!-- <bean id="knife" class="com.tutorial.spring.Knife"/> -->
<bean id="gunPlayer" class="com.tutorial.spring.Player"/>
<bean id="gunPlayer2" class="com.tutorial.spring.Player2"/>
</beans>
import javax.inject.Inject;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
public class Player {
// 속성값에 붙일 수 있다
@Inject
private Weapon weapon;
Player(){
}
//@Inject 생성자에도 붙일 수 있다
public Player(Weapon weapon) {
super();
this.weapon = weapon;
}
//@Inject 새터에도 붙일 수 있다
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public Weapon getWeapon() {
return weapon;
}
public void usePlayerWeapon() {
weapon.useWeapon();
}
//@Inject 일반 매서드에서도 붙일 수 있다
public void setPlayerWeaponNow(Weapon weapon) {
}
}
public class Main {
public static void main(String[] args) {
String xmlConfigPath = "classpath:appContext.xml";
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(xmlConfigPath);
Player gunPlayer = ctx.getBean("gunPlayer", Player.class);
gunPlayer.usePlayerWeapon();
}
}
// 결과
Use Gun
| List 자료구조로 모든 스프링 빈들 주입받기
List 자료구조로 주입받고자 하는 타입으로 필드를 클래스에 선언하게 되면 스프링 프레임워크는 해당 타입에 맞는 모든 스프링 빈을 주입한다.
@Repository
public interface BookRepository {
}
@Repository
public class MyBookRepository implements BookRepository {
}
@Repository
public class BSRepository implements BookRepository {
}
@Service
public class BookService {
@Autowired
List<BookRepository> bookRepository;
public void printBookRepository(){
this.bookRepository.forEach(System.out::println);
}
}
-- 출력 --
com.saelobi.springtutorial.BSRepository@1c98290c
com.saelobi.springtutorial.MyBookRepository@172ca72b
'Spring Framework > Spring 입문 - 개념 및 핵심' 카테고리의 다른 글
[Spring] 스프링(Spring) MVC 아키텍처/설계 구조 (0) | 2020.12.21 |
---|---|
[Spring] 어노테이션(Annotation)을 이용한 스프링 설정 (0) | 2020.12.21 |
[Spring] 스프링 컨테이너(Spring Container)와 빈(Bean) 객체 생명 주기 및 init-method, destroy-method, @PostConstruct, @PreDestroy (0) | 2020.12.17 |
[Spring] 스프링(Spring) @Qualifier, @Named, @Primary 의존객체 선택 (0) | 2020.12.17 |
[Spring] 스프링 빈 범위 지정(Spring Bean Scope), 싱글턴(Singleton), 프로토타입(Prototype) (0) | 2020.12.17 |
[Spring] 여러개로 나뉜 Spring XML 설정파일 합치기 (0) | 2020.12.17 |
[Spring] Spring에서 새터(Setter)로 리스트(List), 맵(Map) 자료구조 주입 (0) | 2020.12.17 |
[Spring] 의존성 주입, DI(Dpendency Injection), 스프링(Spring) 의존성 주입 (0) | 2020.12.17 |