의존 대상을 설정 코드에서 직접 주입하지 않고 스프링이 자동으로 의존하는 빈 객체를 주입 해주는 기능을 자동 주입이라고 한다.
// 빈 설정
@Configuration
public class Config(){
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
@Bean
public RegisterService registerService(){
return new RegisterService(memberDao()); // 의존 주입
}
}
// 의존 주입
public Class RegisterService(){
MemberDao memberDao;
public RegisterService(MemberDao memberDao){
this.memberDao = memberDao; //의존 주입
}
}
// 빈 설정
@Configuration
public class Config(){
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
@Bean
public RegisterService registerService(){
return new RegisterService();
}
}
// 의존 주입
public Class RegisterService(){
@Autowired// 필드에 사용할 경우
MemberDao memberDao;
//--------------------------------------------------
@Autowired // 메서드에 사용할 경우
MemberDao memberDao;
public RegisterService(MemberDao memberDao){
this.memberDao = memberDao;
}
}
@Autowired 어노테이션을 주입하려는 필드나 메서드에 사용하면 스프링이 자동으로 Context에 등록된 빈을 찾아서 할당해 준다.
@Autowired 어노테이션 주의할 점
// 빈 설정
@Configuration
public class Config(){
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
@Bean
public RegisterService registerService1(){
return new RegisterService();
}
@Bean
public RegisterService registerService2(){
return new RegisterService();
}
// 오류 발생
}
자동 주입 가능한 빈이 두 개 이상이면 자동 주입할 빈을 지정할 수 있는 방법이 필요하다. 이때 @Qualifier 어노테이션을 사용하면 자동 주입 대상 빈을 한정할 수 있다.
@Bean
@Qualifier("register")
public RegisterService registerService1(){
return new RegisterService();
}
@Bean
public RegisterService registerService2(){
return new RegisterService();
}
public class MemberSummaryPrinter extends MemberPrinter {
@Override
public void print(Member member) {
System.out.printf(
"회원 정보: 이메일=%s, 이름=%s\n",
member.getEmail(), member.getName());
}
}
@Configuration
public class AppCtx {
// ... 생략
@Bean
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
public MemberSummaryPrinter memberPrinter2() {
return new MemberSummaryPrinter();
}
}
위에 코드를 살펴보면 MemberSummaryPrinter 메서드는 MemberPrinter를 상속 받고 있다. AppCtx에서 memberPrinter1, memberPrinter2가 각각MemberPrinter, MemberSummaryPrinter를 빈에 등록하면 익셉션이 발생한다. 왜냐하면 MemberSummaryPrinter는 MemberPrinter 클래스를 상속 받고 있기 때문에 MemberSummaryPrinter는 MemberPrinter에도 할당 받을 수 있기 때문에 스프링에서는 어떤 클래스를 빈에 등록할지 모르기 때문이다.
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter")
public MemberSummaryPrinter memberPrinter2() {
return new MemberSummaryPrinter();
}
각 메서드에 @Qualifier 어노테이션을 사용해 메서드를 지정할 경우 스프링에서 어떤 클래스를 빈으로 등록할지 명확하게 알 수 있기 때문에 익셉션 오류를 피할 수 있다.
public class MemberListPrinter {
private MemberDao memberDao;
private MemberPrinter printer;
// ...
@Autowired
public void setMemberPrinter(MemberSummaryPrinter printer) {
this.printer = printer;
}
MemberListPrinter 메서드에 직접적으로 MemberSummaryPrinter를 주입 받도록 설정하면 된다. MemberSummaryPrinter는 단 하나만 존재하므로 스프링에서 빈으로 등록이 가능하다.
public class MemberPrinter {
private DateTimeFormatter dateTimeFormatter;
public void print(Member member) {
if (dateTimeFormatter == null) {
System.out.printf(
"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n",
member.getId(), member.getEmail(),
member.getName(), member.getRegisterDateTime());
} else {
System.out.printf(
"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%s\n",
member.getId(), member.getEmail(),
member.getName(),
dateTimeFormatter.format(member.getRegisterDateTime()));
}
}
@Autowired
public void setDateFormatter(DateTimeFormatter dateTimeFormatter) {
this.dateTimeFormatter = dateTimeFormatter;
}
// ...
MemberPrinter 객체는 setDateFormatter 메서드가 null 인지에 여부에 따라 날짜 형식을 바꿔 출력하는 객체이다.
@Autowired 어노테이션는@Autowired 어노테이션이 붙인 타입에 해당하는 빈이 null일 경우(존재하지 않을 경우) 익셉션을 발생한다.
required = false
@Autowired(required = false)
로 설정하면 익셉션을 발생시키지 않고 자동 주입을 하지 않는다.Optional
@Autowired
public void setDateFormatter(Optional<DateTimeFormatter> formatterOpt) {
if (formatterOpt.isPresent()) {
this.dateTimeFormatter = formatterOpt.get();
} else {
this.dateTimeFormatter = null;
}
}
@Nullable 어노테이션
@Autowired
public void setDateFormatter(@Nullable DateTimeFormatter dateTimeFormatter) {
this.dateTimeFormatter = dateTimeFormatter;
}
@Autowired 어노테이션의 required 속성을 false로 할 때와 차이점은 @Nullable 어노테이션을 사용하면 자동 주입할 빈이 존재하지 않아도 메서드가 호출 된다는 점이다. @Autowired 어노테이션의 경우 required 속성이 false인데 대상 빈이 존재하지 않을 경우 세터 메서드를 호출하지 않는다. 즉 null 값을 전달하지 않는다.