스프링은 스프링 컨테이너에 빈으로 등록된 객체를 담아 관리하며, 해당 객체들을 필요로 하는 곳에 자동으로 주입함. 또한 스프링 컨테이너가 관리하는 빈이어야만 의존성 주입을 받을 수 있음. 즉 주입받는 쪽과 주입되는 쪽이 모두 빈이어야 함

의존성 주입에는 @Autowired를 사용하는 등의 방법이 있지만 권장되는 방식은 생성자 주입

@Service
public class UserService {

		// 사용할 필드를 명시하고
    private final EmailService emailService; 
    
    // 생성자를 작성하면 스프링 컨테이너가 주입
    public UserService(EmailService emailService) { 
        this.emailService = emailService;
    }
}

만약 Lombok을 사용한다면 이렇게 줄일 수 있음

@Service
@RequiredArgsConstructor
public class UserService {
    private final EmailService emailService; // final 필수!
}

이렇게 해 두고, 의존성 주입 관련 Config 객체를 별도로 두어 설정할 수 있음

이것의 목적은 저 EmailService가 인터페이스일 때, 구체적으로 주입되는 구현체를 정할 수 있음

@Configuration
public class AppConfig {
    
    @Bean
    public EmailService emailService() {
        return new GmailService();
        //return new NavermailService();
        //return new HanmailService();
    }
}

이렇게 하면 필요한 객체가 바뀔 때 서비스 로직을 직접 수정하는 것이 아닌 config만 수정하면 됨

UserService에서는 emailService가 어떤 객체로 들어오든 그저 자신의 로직을 수행

즉 객체 생성과 비즈니스 로직 수행이라는 관심사를 분리할 수 있음