스프링이 자동으로 의존하는 빈 객체를 주입해주는 기능을 자동 주입이라 한다. 자동 주입을 위해서는 @Autowired 나 @Resource 어노테이션을 사용하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class ChangePasswordService {
// 의존성 자동 주입
// 필드에 @Autowired 사용
@Autowired
private MemberDao memberDao;
...
}
// 또는
public class ChangePasswordService {
private MemberDao memberDao;
// setter 메서드에도 사용할 수 있다.
// setter에 @Autowired를 사용하면 스프링은 타입이 일치하는
// 빈 객체를 찾아 주입한다.
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
}
|
cs |
만약 의존 자동 주입이 필요한 빈이 존재하지 않다면, 다음과 같은 에러가 발생한다.
만약 의존 자동 주입 대상에 일치하는 빈이 두 개 이상이면, 다음과 같은 에러가 발생한다.
@Qualifier 애노테이션을 이용한 의존 객체 선택
@Qualifier 어노테이션을 사용하면 자동 주입 대상 빈을 한정할 수 있다. 따라서 의존 자동 주입 대상에 일치하는 빈이 두 개 이상일 때, 빈을 특정지을 수 있다.
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
|
@Configuration
public class Config {
@Bean
// @Qualifier 로 빈을 특정 짓는다.
@Qualifier("bean")
public setter.Bean getBean1() {
return new setter.Bean();
}
@Bean
public setter.Bean getBean2() {
return new setter.Bean();
}
}
@Component
public class A {
private Bean bean;
@Autowired
// 특정지은 빈을 setter에 명시한다.
@Qualifier("bean")
public void setBean(Bean bean) {
this.bean = bean;
}
}
|
cs |
빈 이름과 기본 한정자
빈 설정에 @Qualifier 어노테이션이 없으면 빈의 이름을 한정자로 지정한다. @Autowired 어노테이션도 @Qualifier 가 없으면 필드나 파라미터 이름을 한정자로 사용한다.
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
|
@Configuration
public class Config {
@Bean
public setter.Bean getBean1() {
return new setter.Bean();
}
@Bean
public setter.Bean getBean2() {
return new setter.Bean();
}
}
@Component
public class A {
@Autowired
// Config 클래스의 getBean1을 한정자로 사용
private Bean getBean1;
public void setGetBean1(Bean bean) {
this.getBean1 = bean;
}
}
|
cs |
상위/하위 타입 관계와 자동 주입
SubBean이 Bean을 extends하고 있다 해보자.
1
2
3
4
5
6
|
public class Bean {
}
public class SubBean extends Bean{
}
|
cs |
그 후 다음과 같은 코드를 실행하면 자동 의존 주입 대상과 일치하는 빈이 두 개라는 에러가 발생한다.
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
|
@Configuration
public class Config {
@Bean
public setter.Bean getBean1() {
return new setter.Bean();
}
@Bean
public setter.SubBean getBean2() {
return new setter.SubBean();
}
}
@Component
public class A {
@Autowired
private Bean bean;
public void setGetBean1(Bean bean) {
this.bean = bean;
}
}
|
cs |
이 에러가 발생하는 이유는 SubBean이 Bean을 extends 하고 있기 때문에 Bean에 Bean과 SubBean 두 타입의 빈을 주입할 수 있기 떄문이다. 이 문제 역시 위에서 언급한 @Qualifier 어노테이션을 사용해 해결할 수 있다. 또는 A 클래스 내에 존재하는 Bean을 SubBean으로 변경하면 된다.
@Autowired 어노테이션의 필수 여부
@Autowired 어노테이션을 붙인 타입에 해당하는 빈이 없으면 exception이 발생한다. 만약 빈이 존재하지 않는 경우 어떤 로직을 수행해야 한다면, required 속성을 false로 두면 된다. 그러면 매칭되는 빈이 없어도 exception이 발생하지 않는다.
1
2
3
4
5
6
7
8
9
10
11
|
@Component
public class A {
@Autowired(required = false)
private Bean bean;
public void setGetBean1(Bean bean) {
this.bean = bean;
}
}
|
cs |
또는 @Autowired 를 그래도 두고, Optional을 사용해도 된다.
1
2
3
4
5
6
7
8
9
10
11
|
@Component
public class A {
private Bean bean;
@Autowired
public void setGetBean1(Optional<Bean> bean) {
///
}
}
|
cs |
또는 @Nullable 어노테이션을 사용하면 된다. @Nullable은 스프링이 제공하는 어노테이션으로, 자동 주입할 빈이 존재하지 않으면 null을 주입한다.
1
2
3
4
5
6
7
8
9
10
11
|
@Component
public class A {
@Autowired
@Nullable
private Bean bean;
public void setGetBean1(Bean bean) {
this.bean = bean;
}
}
|
cs |
@Autowired(required=false)와 @Nullable을 setter에 사용했을 때의 차이는 @Autowired(required=false)를 사용하고 대상 빈이 존재하지 않으면 해당 메서드를 호출하지 않는다는 것이다. 그에 반해 필드 주입에서의 @Autowired(required=false)와 @Nullable은 둘 다 대상 빈이 존재하지 않으면 null을 주입한다.
자동 주입과 명시적 의존 주입 간의 관계
설정클래스에서 행해지는 의존 주입과 자동 주입이 동시에 진행된다면 @Autowired를 통한 자동 주입이 우선순위를 갖는다. 따라서 @Autowired 어노테이션을 사용한다면 설정 클래스에성 객체를 주입하지 말고, 스프링이 제공하는 자동 주입 기능을 사용하는 것이 좋다.
@Autowired, @Resource, @Inject
@Autowired, @Resource, @Inject 어노테이션들은 모두 의존성 주입에 사용되는 어노테이션들이다. @Autowired는 org.springframework,beans.factory.annotation에 존재한다. 그에 반해 @Resouce는 javax.annotation.Resource에, @Inject는 javax.inject.Inject에 존재하며 자바에서 지원하는 어노테이션들이다.
이 어노테이션들은 의존 객체를 찾을 떄 찾는 순서가 다르다. 또 한, @Autowired와 @Inject 어노테이션은 멤버 변수, setter, 생성자, 일반 메서드에 모두 적용 가능하지만 @Resource는 오직 멤버 변수와 setter 메서드에만 적용할 수 있다.
@Resource
이름 -> 타입 -> @Qualifier -> 실패
@Autowired
타입 -> 이름 -> @Qualifier -> 실패
@Inject
타입 -> @Qualifier -> 이름 -> 실패
Bean 강제 지정
위의 3가지 어노테이션 모두 @Qualifier 어노테이션을 통해 자동 주입 대상 빈을 지정할 수 있다. 또는 javax.inject에 존재하는 @Named 어노테이션을 사용해도 된다. @Resource 어노테이션의 경우 name 값을 주어 자동 주입 대상 빈을 지정할 수도 있다.
Bean이 없을 경우 처리
Bean이 존재하지 않는다면 @Resource, @Inject는 애러를 발생시킨다. @Autowired 역시 디폴트로는 에러를 발생시키지만 required를 false로 주어서 빈이 없어도 에러를 발생시키지 않을 수 있다는 점이 다르다.
출처 - 초보 웹 개발자를 위한 스프링 5 프로그래밍 입문