티스토리 뷰

반응형

부제: @Autowired @Resource 차이, Spring @Qualifier, Spring Annotation 종류



 Spring의 핵심 개념 중 하나인 DI는 Dependency Injection의 약자이다. 이 포스팅에서는 DI와 의존(Dependency)에 대한 자세한 설명은 하지 않고, 위키피디아의 설명으로 대신하겠다.


프로그래밍에서 구성요소간의 의존 관계가 소스코드 내부가 아닌 외부의 설정파일 등을 통해 정의되게 하는 디자인 패턴 중의 하나이다.


 한편, 특정 객체에 의존 객체를 주입하는 방식은 두가지이다.


 1. 생성자를 통한 주입.

 2. Setter 메소드를 통한 주입.


이는 각각 XML로 아래와 같이 구현할 수 있으며, 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="studentDao" class="com.member.StudentDao">
    </bean>
    <bean id="professorDao" class="com.member.ProfessorDao">
    </bean>
    
    <bean id="university" class="com.University">
        <!— 생성자 주입방식 —>
        <constructor-arg ref="studentDao"/>
        <!— Setter 메소드 주입방식 —>
        <property name="professorDaoMethod" ref="professorDao"/>
    </bean>
    
</beans>

JAVA 소스코드는 아마 아래와 같은 방식으로 구현될 것이다.


public class University {

    private StudentDao studentDao;
    private ProfessorDao professorDao;

    public University (StudentDao studentDao) {

        this.studentDao = studentDao;
    }

    public void setProfessorDaoMethod(ProfessorDao professorDao) {

        this.professorDao = professorDao;
    }
    // 이하 생략
}

 생성자 주입 방식과 Setter 메소드를 활용한 주입 모두 ref 속성에 bean객체의 id(이름)을 적어 넣어 처리했다. Setter 메소드 주입방식의 경우 name 속성에 setter메소드 명을 넣은 것이 눈에 띈다. (생성자 주입 방식은 객체 생성과 동시에 주입됨.)



 위와 같은 방법 외에도, JAVA 소스코드 내에서 간단하게 처리할 수 있는 방법이 있다. 그래서 ApplicationContext.xml 파일에는 Bean 등록만 해놓고, DI에 관련된 내용은 JAVA 소스코드 내부에서 처리하는 경우가 꽤 있다.


그 방법은 @Autowired@Resource 이다.


 University.java를 아래와 같이 작성하면 ApplicationContext.xml에서는 bean 객체 등록만 하면 된다. (constructor-arg, property등을 작성할 필요 없다.)


public class University {

    @Autowired
    private StudentDao studentDao;
    private ProfessorDao professorDao;

/*  @Autowired // 이렇게 생성자에 붙여줘도 된다. 
    public University (StudentDao studentDao) {

        this.studentDao = studentDao;
    }*/

    @Resource(name="professorDao")
    public void setProfessorDaoMethod(ProfessorDao professorDao) {

        this.professorDao = professorDao;
    }
    // 이하 생략
}

  생성자 주입 방식에 @Autowired를 사용했고, Setter 메소드 주입에 @Resource를 사용한 모습이다. 그렇다면 @Autowired와 @Resource는 어떤 차이가 있을까.


 @Autowired 또는 @Resource를 사용하면 해당 어노테이션을 적용한 변수와 맞는 적절한 의존 객체를 bean 객체들 중에서 찾아 주입한다. 이 때 bean객체의 id와 class 중 어떤 것을 우선하여 검색하는지에 대해 아래와 같은 차이가 있다.


@Autowired: 스프링이 타입(class)을 우선으로 bean 객체를 검색

@Resource: 스프링이 이름(id)을 우선으로 bean 객체를 검색


 그런데 StudentDao를 상속한 CacheStudentDao가 bean에 등록 되었다고 가정해보자. 이러한 상황에서는 @Autowored를 사용해 자동주입을 시도할 경우 오류가 발생한다. StudentDao와 CacheStudentDao 중 어떤 것을 주입해야할지 명시가 안되어있기 때문이다.


 이럴 때는 Qualifier를 사용해 문제를 해결한다.


<bean id="studentDao" class="com.member.StudentDao">
        <qualifier value="AAA"/>
</bean>

 위와 같이 ApplicationContext.xml 파일을 변경한 후

public class University {

    @Autowired
    @Qualifier("AAA")
    private StudentDao studentDao;
    private ProfessorDao professorDao;

    // 이하 생략
}


 위와 같이 @Qualifier 어노테이션을 사용하여 해결할 수 있다. Qualifier를 명시했더라도, 같은 타입의 bean 객체가 1개이면 @Qualifier 어노테이션으로 bean 객체를 특정하지 않아도 된다.


 그러면 이제 @Autowired와 @Resource가 붙은 변수에 대해 적절한 의존 객체를 찾는 과정을 자세히 알아보자.



 @Autowired 어노테이션의 적용순서

1. 타입이 같은 bean 객체를 검색한다. @Qualifier가 있을 경우 Qualifier Value까지 같은 객체를 찾는다.


2. 타입이 같은 bean 객체가 2개 이상이면, @Qualifier가 지정한 bean 객체를 찾는다.


3. 타입이 같은 bean 객체가 2개 이상이고, @Qualifier가 지정되어 있지 않으면, 변수명과 id가 같은 bean 객체를 찾는다.



@Resource 어노테이션의 적용순서

1. @Resource가 지정한 name과 id가 같은 bean 객체를 찾는다.


2. 찾지 못하면, 타입이 같은 bean 객체를 찾는다.


3. 만약 타입이 같은 bean 객체가 2개 이상이면, 변수명과 id가 같은 bean 객체를 찾는다.


4. 그래도 못찾았으면, @Qualifier가 지정한 bean 객체를 찾는다.





-끝-



«   2022/06   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
글 보관함
Total
809,655
Today
26
Yesterday
129