[Spring] 의존객체 자동 주입(Automatic Dependency Injection), @Autowired, @Resource, @Inject

2020. 12. 17. 18:09 Spring Framework/Spring 입문 - 개념 및 핵심

의존객체 자동 주입(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



출처: https://engkimbs.tistory.com/682?category=767795 [새로비]