Circular dependencies
A → B를 참조하고 B → A를 참조할경우 순환 의존관계가 형성되면서
BeanCurrentlyInCreationException 예외가 발생할 수 있습니다.
package org.prgrms.kdtspringorder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
class A{
private final B b;
A(B b){
this.b = b;
}
}
class B{
private final A a;
B(A a){
this.a =a;
}
}
@Configuration
class CircularConfig{
@Bean
public A a(B b){
return new A(b);
}
@Bean
B b(A a){
return new B(a);
}
}
public class CircularDepTester {
public static void main(String[] args) {
var AnnotationConfigApplicationContext = new AnnotationConfigApplicationContext(CircularConfig.class);
}
}
- @ComponetScan을 이용하면 @Bean 없이 빈으로 자동으로 등록
- -각각 인터페이스로부터 레포지토리를 구현함
-컴포넌트 스캔대상으로 하기 위해 @Repository 추가
-MemoryOrderRepository에서 getOrderId 사용하기 위해 Order클래스에 메서드 추가함public UUID getOrderId(){ return orderId; }
생성자
Autowired
-setter
의존관계 주입 방법에는 여러가지가 존재하는데 무엇을 써야할까? 생성자 기반 의존관계 주입 !!!
1 초기화시에 필요한 모든 의존관계가 형성되기 때문에 안전
2 잘못된 패턴 찾을수 있게 도와줌 : 생성자의 매개변수가 여러가지일경우 많은 의존관계를 맺고 있다고 암시 -> 관심사의 분리가 필요한 부분
3 테스트 쉽게해줌 :set 필드 로 의존주입할경우 생성안된 빈에 의해 널포인트예외 발생 가능성 있음
4 불면성을 확보 :생성자 주입을 안하면 final 키워드 불가능
final 키워드 : 한번 만들어진 의존관계가 변하지 않게 도와줌
기존클래스에 VoucherRepository를 구현하는 JdbcVoucherRepository를 생성할 경우 둘다 @Repository가 있기 때문에 componentscan의 대상 두개의 빈이 등록 되기 때문에 아래와 같이 오류가 발생한다.
해결방법? 어떤 빈이 자동등록되는지 선택을 해줘야함 @Primary
1. @primary를 이용하여 빈 등록시 우선순위를 부여
2. 이름을 명시해주고
A서버 B서버 C서버에서 접속 대상이 다를경우
접속을 담당하는 탬플릿 클래스는 동일한데 3개가 등록 되어야함
다같은 타입이어서 충돌이 일어날때 이럴때 퀄리파이이용
대체로 프라이머리
var voucherRepository = BeanFactoryAnnotationUtils.qualifiedBeanOfType(applicationContext.getBeanFactory(),VoucherRepository.class,"memory");
var voucherRepository2 = BeanFactoryAnnotationUtils.qualifiedBeanOfType(applicationContext.getBeanFactory(),VoucherRepository.class,"memory");
System.out.println(MessageFormat.format("voucherRepository {0}",voucherRepository));
System.out.println(MessageFormat.format("voucherRepository2 {0}",voucherRepository));
System.out.println(MessageFormat.format("voucherRepository == voucherRepository2 => {0}", voucherRepository == voucherRepository2));
getBean할때마다 같은 객체가 반환되는 것을 알수 있다. 다르게 하고 싶을때는 prototype을 이용하면 된다.
prototype을 이용했기 때문에 다른 객체가 반환되는 것을 확일할 수 있다.
실행결과
postConstruct called!
afterPropertieSet called!
main 실행
preDestroy called!
destroy called!
public class AppConfiguration {
@Bean(initMethod = "init")
public Beanone beanone(){
return new Beanone();
}
class Beanone implements InitializingBean{
public void init(){
System.out.println("[BeanOne]init called");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("[Beanone] afterPropertiesSet called!");
}
}