목차

스프링5; 의존 자동 주입 @Autowired

🗓️

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(); //<<
}
c3d7272d15d6b70e906ef1fe1ca0679f.png

@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은 메소드 이름이 한정자의 이름이 된다.
4acc026406b7be2469a8c74092f5a1bc.png

상속 관계의 자동 주입

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가 발생했을 때 원인을 찾는데 오랜 시간이 걸릴 수 있다. 의존 자동 주입을 사용한다면 일관되게 사용해야 이런 문제를 줄일 수 있다. 의존 자동 주입을 사용하고 있다면 일부 자동 주입을 적용하기 어려운 코드를 제외한 나머지 코드는 모두 자동주입을 사용한다.