2022년 04월 06일 TIL
DI
Dependency Resoloution Process
- IoC 컨테이너(ApplicationContext)가 configuration metadata에 의해 만들어진다.
- Bean을 생성하며 해당 Bean에 필요한 의존성(Bean)을 제공한다.
Cicular dependencies
- 순환 참조
- A → B, B → A 형태로 참조가 이루어진다.
- A가 생성되기 위해 B가 필요하지만 B가 생성되기 위해 A도 필요하다.
BeanCurrentCreationException
발생
Component scan
스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능
Stereotype Annotation
@Component
@Repository
@Service
@Controller
@Configuration
@Componentscan
현재 패키지를 기준으로 component scan을 한다.
-
basePackages
- 스캔 대상 패키지들의 경로를 하드 코딩한다.
@ComponentScan(basePackages = {"org.prgms.kdt.order", "org.prgms.kdt.voucher"})
-
basePackageClasses
- 컴포넌트 스캔을 위해 기준이 되는 클래스들을 설정
@ComponentScan(basePackageClasses = {Order.class, Voucher.class})
-
excludeFilters
- 제외 대상 설정
- 참고
@Autowired
- 필드 의존성 주입
@Autowired
private VoucherRepository voucherRepository;
- setter 주입
private VoucherRepository voucherRepository;
public void setVoucherRepository(VoucherRepository voucherRepository) {
this.voucherRepository = voucherRepository;
}
- 생성자 의존성 주입
- 생성자가 1개일 경우 자동으로 @Autowired가 설정된다.
- 생성자가 2개일 경우 수동으로 @Autowired가 설정해야 한다.
- 가장 추천 되는 방법이다.
- 초기화시에 필요한 모든 의존관계가 형성되기 때문에 안전하다.
- 잘못된 패턴을 찾을 수 있게 도와준다.
- 테스트를 쉽게 할 수 있도록 해준다. → mocking을 용이하게 한다.
- final 키워드를 이용하여 불변성을 확보할 수 있다. → thread safe하다.
@Primary, @Qualifier
@Primary
interface VoucherRepository { ... }
@Repository
@Primary
class MemoryVoucherRepository implements VoucherRepository { ... }
@Repository
class JdbcVoucherRepository implements VoucherRepository { ... }
자동 주입 가능한 Bean이 2개 이상인 경우 주입 우선순위를 설정하기 위해 사용한다.
@Qualifier
interface VoucherRepository { ... }
@Repository
@Qualifier("memory")
class MemoryVoucherRepository implements VoucherRepository { ... }
@Repository
@Qualifier("jdbc")
class JdbcVoucherRepository implements VoucherRepository { ... }
@Service
class VoucherService {
...
public Voucher Service(@Qualifier("memory") VoucherRepository voucherRepository){ ... }
...
}
- Bean의 사용 용도를 설정하고 DI시 용도에 맞는 Bean을 주입한다.
- 특정 qualified된 Bean의 타입 가지고 오기
VoucherRepository voucherRepository = BasicFactoryAnnotationUtils.qualifiedBeanOfType( applicationContext.getBeanFactory(), VoucherRepository.class, "memory");
- 주입 받는 대상이 어떠한 Bean을 사용할지 걱정하지 않게 하는게 좋다.
- @Primary가 @Qualifier보다 좋은 방법이다.
- 하지만 다수의 템플릿이 있고 접속 대상에 따라 서로 다른 템플릿을 사용하는 경우 @Qualifier를 사용한다.
복수 개의 Bean 설정
- 스프링의 경우 설정할 내용이 많아 파일들을 분리해서 사용한다.
Bean Scope
- singleton: Bean을 오로지 하나만 생성(기본)
@Repository
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class MemoryVoucherRepository implements VoucherRepository { ... }
- prototype: 매번 새로운 Bean을 생성
@Repository
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MemoryVoucherRepository implements VoucherRepository { ... }
Bean LifeCycle Callbacks
applicationContext.close() → IoC 컨테이너 소멸 → 모든 Bean들 소멸 → Callback 발생
- Bean 생성 생명주기 콜백
1)@PostConstruct
적용된 메서드 실행
2) InitializingBean 구현시 afterPropertiesSet 메서드 호출
3)@Bean
어노테이션의 initMethod에 설정한 메서드 호출@Bean(initMethod = "init")
→ init 메서드 호출
- Bean 소멸 생명주기 콜백
1)@PreDestroy
적용된 메서드 실행
2) DisposableBean 구현시 destroy 호출
3)@Bean
어노테이션의 destroyMethod에 설정한 메서드 호출@Bean(destroyMethod = "destroy")
→ destroy 메서드 호출
왜 IoC 컨테이너에서 Bean을 관리하나?
- Bean을 싱글톤으로 관리하기 위해서이다.
- Bean을 싱글톤을 관리하지 않을 경우 기존에 사용하던 Bean과 다른 Bean을 사용할 수 있기에 항상 같은 참조를 유지하기 위해서 싱글톤으로 관리한다.
- 추가)
그 이유는 스프링이 주로 적용되는 대상이 자바 엔터프라이즈 기술을 사용하는 서버환경이기 때문이다. 스프링이 처음 설계되었던 대규모 엔터프라이즈 서버환경은 초당 최대 수십, 수백 개의 요청을 받아 처리하는 높은 성능이 요구되는 환경이었다. 이 때마다 매번 새로운 오브젝트를 생성해서 사용할 경우 아무리 GC의 성능이 좋아졌다고 해도, 서버가 감당하기 힘든 부하가 걸릴 것이다.
Bean이란? Bean Scope와 싱글톤 레지스트리, Bean 생성방식
Author And Source
이 문제에 관하여(2022년 04월 06일 TIL), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yshjft/2022년-04월-06일-TIL저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)