Automatic dependency injection
객체에 붙이는 @Autowired
- 서비스 코드에서 의존주입 받는 객체에 대해 다음과 같이 선언하면 스프링이 bean객체를 직접 찾아서 할당한다
// Service code
@Autowired
private MemberDao memberDao;
- bean 설정에서 의존 주입부분을 삭제하더라도 직접 넣는다
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
// pwdSvc.setMemberDao(memberDao()); << 이부분을 삭제하더라도 알아서 찾아넣는다.
return pwdSvc;
메소드에 붙이는 @Autowired
- 메소드에도 역시 붙이는게 가능하다. setter에 붙인다면 좀 더 명확할 것 같다는 생각을 해본다.
// Service code
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
@Autowired
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
마찬가지로 bean 설정에서 의존부분을 지울 수 있다.
// Bean Config
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter(); //<<
}
@Qualifier; 의존 객체의 선택
- 자동 주입이 가능한 bean이 두개 이상이면 자동 주입할 bean을 지정할 수 있도록 대상을 한정한다.
- 서비스 코드와 bean 설정에서 어노테이션을 붙여주면 된다.
// Bean config
@Bean
@Qualifier("printer") // <<<<
public MemberListPrinter listPrinter() {
return new MemberListPrinter();
}
@Bean
public MemberListPrinter listPrinter2() {
return new MemberListPrinter();
}
// Service code
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
@Autowired
@Qualifier("printer") // <<<<
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
bean 이름과 한정자
- @Qualifier가 지정되지 않은 bean은 메소드 이름이 한정자의 이름이 된다.
상속 관계의 자동 주입
public class StudentSummary extend StudentInformation {
@Override
public void print(Student student){
sout(....)
}
}
- 위의 서비스 코드가 있다고 할때 부모 객체가 bean객체로 만들었다면 예외가 발생한다.
- 상속관계에 있는 객체를 bean객체로 만들었을때 동일한 객체라고 판단한다.
- 이 경우에 @Qualifier 어노테이션을 사용해 주입할 bean을 한정하면 된다.
의존 주입의 필수 여부
- 스프링의 DI중 setter방식의 의존주입이 있다. 그런데 이 방법으로 의존을 주입했을때 @Autowired 어노테이션을 붙이면 의존이 필요하지 않음에도 주입할 객체를 요구하는 경우가 생긴다.
- 자동 주입할 대상의 객체가 필수가 아닌 경우는 @Autowired 어노테이션의 required 옵션을 다음과 같이 false로 주면 된다
// method
@Autowired(required = false)
public void setStudent(Student Student){
this.student = student;
}
// object
public class StudentInformation {
@Autowired(required = false)
private Student student;
}
- 스프링5부터는 아래의 Optional방식을 사용할 수도 있다.
// method
@Autowired
public void setStudent(Optional<Student> student){
if (student.isPresent()){
this.student = student.get();
} else {
this.student = null;
}
}
// object
public class StudentInformation {
@Autowired
private Optional<Student> studentOptional;
public void print(Student student){
Student student = studentOptional.orElse(null);
if (student == null){
//..
}
}
}
//...
- @Nullable 어노테이션도 가능하다.
//method
public class StudentInformation {
private Student student;
public void print(Student student){
//..
}
@Autowired
public void setStudent(@Nullable Student student){
this.student = student;
}
}
// object
public class StudentInformation {
@Autowired
@Nullable
private Student student;
// ..
}
위의 @Autowired의 requied와 차이점은 자동주입 되는 시점에 bean이 존재하지 않아도 메소드가 호출된다는 점이다. 그리고 의존 주입 대상객체가 존재하지 않으면 null값을 반환한다.
의존 자동 주입의 유의점
- 자동 주입을 하는 코드와 수동으로 주입하는 코드가 섞여 있으면 주입을 제대로 하지 않아서 NPE가 발생했을 때 원인을 찾는데 오랜 시간이 걸릴 수 있다. 의존 자동 주입을 사용한다면 일관되게 사용해야 이런 문제를 줄일 수 있다. 의존 자동 주입을 사용하고 있다면 일부 자동 주입을 적용하기 어려운 코드를 제외한 나머지 코드는 모두 자동주입을 사용한다.