생성자 @Autowired
@Service
public class BookService {
BookRepository bookRepository;
@Autowired
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
실행결과
@Repository 추가 - Bean등록
@Repository
public class BookRepository {
}
그래 인정! 생성자이기 때문에 BookService에 대한 빈을 생성하지 못하는구나.
Bookservice bookService = new BookService(bookRepository); -> 불가!
Setter @Autowired
bookRepository에 대한 Bean을 생성하지 않은 상태 (즉 @Repository 설정 안 함)
@Service
public class BookService {
BookRepository bookRepository;
@Autowired
public void setBookRepository(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
그렇다면 생성자도 아닌 Setter인대 적어도 BookService에 대한 Bean은 생성되야하는 것이 정상 아닐까?
@Autowired를 작성하여서
의존성을 주입하려고 하기 때문이다.
이때 required = false를 주어 Optional로 만들어 버리면 된다.
@Service
public class BookService {
BookRepository bookRepository;
@Autowired(required = false)
public void setBookRepository(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
@SpringBootApplication
public class Demospring51Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(Demospring51Application.class, args);
String[] beanDefinitionNames = run.getBeanDefinitionNames();
System.out.println(Arrays.toString(beanDefinitionNames));
}
}
Field @Autowired
@Service
public class BookService {
@Autowired(required = false)
BookRepository bookRepository;
}
경우의 수
- 해당 타입의 빈이 없는 경우
- 해당 타입의 빈이 한 개인 경우
- 해당 타입의 빈이 여러 개인 경우
특정 타입의 빈이 여러 개인 경우
public interface BookRepository {
}
@Repository
public class MyBookRepository implements BookRepository{
}
@Repository
public class JunwooBookRepository implements BookRepository{
}
이때 스프링은 어떤 BookRepository를 주입해줄까?
@Service
public class BookService {
@Autowired
BookRepository bookRepository;
}
스프링이 어떤 타입을 주입해야 할지 모르기 때문이다.
@Primary : 여러 가지 동일한 Bean을 주입해야 할 경우에 특정 빈을 사용할 것이라고 지정하는 애노테이션
@Repository @Primary
public class JunwooBookRepository implements BookRepository{
}
확인 : BookService 빈 생성 시 어떠한 빈을 주입받는지
@Service
public class BookService {
@Autowired
BookRepository bookRepository;
public void printBookRepository() {
System.out.println(bookRepository.getClass());
}
}
@Component
public class BookServiceRunner implements ApplicationRunner {
@Autowired
BookService bookService;
@Override
public void run(ApplicationArguments args) throws Exception {
bookService.printBookRepository();
}
@Qualifier("small case의 클래스명") : 주입받을 빈을 명시하는 방법
@Service
public class BookService {
@Autowired @Qualifier("myBookRepository")
BookRepository bookRepository;
public void printBookRepository() {
System.out.println(bookRepository.getClass());
}
}
같은 타입의 모든 Bean을 주입받을 때 : List 선언
@Service
public class BookService {
@Autowired
List<BookRepository> bookRepository;
public void printBookRepository() {
this.bookRepository.forEach(System.out::println);
}
}
필드 명을 주입받을 Bean의 small case를 작성하여 주입
@Service
public class BookService {
@Autowired
BookRepository junwooBookRepository;
public void printBookRepository() {
System.out.println(this.junwooBookRepository.getClass());
}
}
동작원리
BeanPostProcessor
빈의 인스턴스를 생성한 다음 빈의 초기화 라이프사이클(initialization) 이전 이후에 또 다른 작업을 할 수 있는 라이프사이클 콜백이 있다.
이를 BeanPostProcessor라고 한다.
Bean 인스턴스가 만들어지고 나서 부가적인 처리를 하는 방법 두 가지
1. 애노테이션 사용
@PostConstruct
public void setUp() {
}
2. InitailiInitializingBean 구현
@Service
public class BookService implements InitializingBean {
@Autowired
BookRepository junwooBookRepository;
public void printBookRepository() {
System.out.println(this.junwooBookRepository.getClass());
}
@Override
public void afterPropertiesSet() throws Exception {
}
}
즉 Bean 초기화 이전에
AutowiredAnnotationBeanPostProcessor 발동하여 @Autowired를 처리한다.
(빈의 주입)
@Service
public class BookService {
@Autowired
BookRepository junwooBookRepository;
// public void printBookRepository() {
// System.out.println(this.junwooBookRepository.getClass());
// }
@PostConstruct
public void setUp() {
System.out.println(this.junwooBookRepository.getClass());
}
}
찍히는 곳이 다른데...?
이전의 라이프사이클은 애플리케이션 구동이 완료되고 처리되지만
현재의 라이프사이클은 애플리케이션 구동 중에 처리된다.
일반적인 Bean들에게
BeanPostProcessor의 애노테이션 처리 로직을 적용한다.
AutowiredAnnotationBeanPostProcessor가 빈으로 등록되어있는지 확인
@Component
public class BookServiceRunner implements ApplicationRunner {
@Autowired
BookService bookService;
@Autowired
ApplicationContext applicationContext;
@Override
public void run(ApplicationArguments args) throws Exception {
//bookService.printBookRepository();
AutowiredAnnotationBeanPostProcessor bean = applicationContext.getBean(AutowiredAnnotationBeanPostProcessor.class);
System.out.println(bean);
}
}
코드 참조
https://github.com/mike6321/Spring/tree/master/Spring/demospring51
'Spring > Spring' 카테고리의 다른 글
(SPRING) IoC 컨테이너 - 빈의 스코프 (0) | 2020.01.01 |
---|---|
(SPRING) IoC 컨테이너 - @Component와 컴포넌트 스캔 (0) | 2020.01.01 |
(SPRING) IoC 컨테이너 - ApplicationContext와다양한 빈 설정 방법 (0) | 2020.01.01 |
(SPRING) IoC 컨테이너 - 스프링 IoC 컨테이너와 빈 (0) | 2019.12.31 |
(SPRING) 스프링 AOP : 애노테이션 기반 AOP (0) | 2019.12.25 |