의존이란?
- 서비스 객체가 있을때 비즈니스 로직을 처리하는 경우 저장소의 객체를 직접 들여다 볼 수 있다.
public class StudentRegisterService {
    private StudentRepositody studentRepository = new StudentRepository();
    //...
    public void register(Request request)
        //..
        Student student = studentRepository.findByName(studentName);
        if(student != null){
            //..
        }
}위와 같은 코드가 있을때 서비스 객체를 생성한다면 자연스럽게 저장소 객체도 생성된다.
- 이 경우를 두고 ‘서비스가 저장소에 의존된다’라고 말한다.
- 의존경우가 있을 경우엔 어떤 일이 생길까?
위와같이 모든 서비스 코드에서 의존관계가 종속된다면 의존에 관련된 코드를 수정 할 때 마다 서비스코드도 전부 수정해야한다.
DI를 통한 의존관계 처리
- 생성자를 통해 객체를 받아서 처리하면 의존관계를 해결할 수 있다.
public class StudentRegisterService {
    private StudentRepositody studentRepository;
    public class StudentRegisterService(StudentRepositody studentRepository){
        this.studentRepository = studentRepository; // << 이와같이 Constructor로 받으면 해결된다.
    }
    //...
    public void register(Request request)
        //..
        Student student = studentRepository.findByName(studentName);
        if(student != null){
            //..
        }
}- 스프링의 DI는 여러가지 방법이 있는데 크게 3가지만 아래 정리해보겠다.
Constructor 방식
- 서비스코드는 위와 같고 bean 설정은 아래와 같다
//...
@Bean
public MemberDao memberDao() {
    return new MemberDao();
}
@Bean
public StudentRegisterService studentRegisterService() {
    return new StudentRegisterService(memberDao());
}
//...객체를 생성하는 각각의 메소드를 만들어 주입하면 된다.
- 생성자 방식의 특징- 주입받은 객체를 완전한 상태로 사용할 수 있다. → 모든 인자를 반드시 받아야 하므로
- 대신 받아야할 객체가 많을 때는 일일이 필요한 객체를 확인해야하는 단점이 있다
 
Setter방식
- 아래와 같이 서비스 코드에 setter메소드를 추가한다
//...
public void setMemberDao(MemberDao memberDao) {
    this.memberDao = memberDao;
}
public void setPrinter(MemberPrinter printer) {
    this.printer = printer;
}
//...- 그리고 아래와 같이 bean설정에 넣는다.
@Bean
public MemberDao memberDao() { 
    return new MemberDao();
}
@Bean
public MemberPrinter memberPrinter() {
    return new MemberPrinter();
}
    @Bean
    public MemberInformationPrinter memberInformationPrinter() {
        // setter 방식
        MemberInformationPrinter informationPrinter = new MemberInformationPrinter();
        informationPrinter.setMemberDao(memberDao()); // << 의존 주입
        informationPrinter.setPrinter(memberPrinter()); // << 의존 주입
        return informationPrinter;
    }constructor방식과 다르게 객체를 먼저 생성한 다음 setter에 객체를 전달한다.
- setter방식의 특징- 코드를 따라 자연스럽게 필요한 객체를 모두 알 수 있다.
- 필요한 의존객체를 모두 전달하지 않아도 객체가 생성되기 때문에 NPE에 유의해야 한다.
 
일반 상수값 전달 방식
- 꼭 객체가 아니더라도 일반 상수값을 전달 할 수도 있다.
@Bean
public VersionPrinter versionPrinter() {
    VersionPrinter versionPrinter = new VersionPrinter();
    versionPrinter.setMajorVersion(5); // <<
    versionPrinter.setMinorVersion(0); // <<
    return versionPrinter;
}@Autowired
- 스프링 빈에 의존하는 다른 빈을 자동으로 주입해준다. 아래 bean 설정의 선언부분에 어노테이션을 붙이면
public MemberDao memberDao() {
        return new MemberDao();
    }
// 이 코드를 아래와 같이 바꾸면 객체를 자동으로 @Bean어노테이션을 사용하는 메소드에 붙여준다.
@Autowired
private MemberDao memberDao;
// ...
// 아래와 같이 bean 생성 코드 안에서 객체를 선언할 필요가 없다
@Bean
public MemberListPrinter listPrinter() {
    return new MemberListPrinter(memberDao(), memberPrinter());
    // 이 코드 역시 아래와 같이 바꿀 수 있다.
    return new MemberListPrinter(memberDao, memberPrinter); //<<<
}@Import
- 두개 이상의 빈 설정 코드를 사용한다면 다음과 같이 최상위 빈 설정 코드에 선언하면 된다
@Configuration
@Import({AppConf1.class, AppConf2.class})
public class AppConfigurationMaster {
    //...
}

