[Spring] Spring IoC Container, BeanScan, ์๋ช ์ฃผ๊ธฐ, ์ค์ฝํ
- ์ ์ด์ ์ญ์ : ๊ฐ์ฒด์ ์์ฑ์์๋ถํฐ ์๋ช ์ฃผ๊ธฐ์ ๊ด๋ฆฌ๊น์ง ๋ชจ๋ ๊ฐ์ฒด์ ๋ํ ์ ์ด๊ถ์ด ๋ฐ๋์๋ค๋ ๊ฒ์ ์๋ฏธ
1) DI : Dependency Injection
์์ฑ์, ํ๋, setter
๋์ ์ผ๋ก ์์กด์ฑ ์ฃผ์ -> ์์ง๋ ๋ฎ์ถค
๋๋ฒ๊น ์ด๋ ค์ + ํ ์คํธ ์ฝ๋ ์ง๊ธฐ ์ด๋ ค์
2) DL : Depnedency LookUp
์์กด๊ด๊ณ๊ฐ ํ์ํ ๊ฐ์ฒด์์ ์ง์ ๊ฒ์ํ๋ ๋ฐฉ์
1) ์์ฑ์ ์ฃผ์
- ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋, ์์กด์ฑ์ ๊ฐ์ ํ ์ ์์
private final MasterService;
MentorController(MasterService masterService ){
this.masterService = masterService;
}
- ์ํ์ฐธ์กฐ ์๋ฐฉ
2) ํ๋ ์ฃผ์
3) setter
- ํ์ํ ๋๋ง ์ธ๋ถ์์ ๋ฐ์์ ์ฌ์ฉ ๊ฐ๋ฅ
1) ์ ์ญ์ ์ผ๋ก ๊ฐ์ฒด๊ฐ์ ์์กด๊ด๊ณ๋ฅผ ์ค์
2) ๋ฐ๋ณต์ ์ธ ๊ฐ์ฒด ์์ฑ x
BeanFactory์ ํ์ ์ธํฐํ์ด์ค๊ฐ ApplicationContext๊ฐ Spring์์ ๋งํ๋ IoC Container๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค
๊ฐ์ฒด ์์กด์ฑ์ ์ญ์ ์์ผ ๊ฐ์ฒด ๊ฐ์ ๊ฒฐํฉ๋๋ฅผ ์ค์ด๊ณ , ์ ์ฐํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ํ์ฌ
๊ฐ๋ ์ฑ ๋ฐ ์ฝ๋ ์ค๋ณต, ์ ์ง ๋ณด์๋ฅผ ํธํ๊ฒ ํ ์ ์์
ApplicationContext์ ๋๋ค๋ฅธ ๊ธฐ๋ฅ์ผ๋ก๋ AOP์์ ์ฌ์ด ํตํฉ, ๋ฉ์์ง ๋ฆฌ์์ค ์ฒ๋ฆฌ(๊ตญ์ ํ), ์ด๋ฒคํธ ๊ฒ์๊ฐ ์๋ค
ApplicationContext ์ ์์ ํด๋์ค ๋ก ์ธํด ์๋ฐ์ฝ๋, XML ๋ฑ์ผ๋ก ์ค์ ๊ฐ๋ฅ
1) AnnotationConfigApplicationContext(AppConfig.class)
2) GenericXmlApplicationContext(appConfig.xml)
IoC Container ์์ฑ -> ๋น ์์ฑ -> ์์กด ๊ด๊ณ ์ฃผ์ -> ์ด๊ธฐํ ์ฝ๋ฐฑ ๋ฉ์๋ ํธ์ถ@PostConstruct -> ์ฌ์ฉ -> ์๋ฉธ์ ์ฝ๋ฐฑ ๋ฉ์๋ ํธ์ถ@PreDestroy -> ์คํ๋ง ์ข ๋ฃ
์ฑ๊ธํค ๊ฐ์ฒด๋ ์ํ๋ฅผ ์ ์งํ๊ฒ ์ค๊ณํ๋ฉด ์๋๋ค
๋ฌด์ํ๋ก ์ค๊ณํด์ผ ํ๋ค
1) ํน์ ํด๋ผ์ด์ธํธ๊ฐ ์์กด์ ์ธ ํ๋๊ฐ ์์ผ๋ฉด ์๋๋ค
2) ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ํ๋๊ฐ ์์ผ๋ฉด ์๋๋ค
public class StatefulService {
private int price; // ์ํ๋ฅผ ์ ์งํ๋ ํ๋
public void order(String name, int price){
System.out.println("name= "+ name + " price = " + price);
this.price = price; // ์ฌ๊ธฐ๊ฐ ๋ฌธ์ !
}
public int getPrice(){
return price;
}
}
public class StatefulServiceTest {
@Test
void statefulServiceSingleton() {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
StatefulService statefulService = ac.getBean("statefulService", StatefulService.class);
StatefulService statefulService2 = ac.getBean("statefulService", StatefulService.class);
statefulService.order("userA", 10000);
statefulService2.order("userB", 20000);
int price = statefulService.getPrice();
System.out.println(price); // 20000
Assertions.assertThat(statefulService.getPrice()).isEqualTo(20000);
}
static class TestConfig {
@Bean
public StatefulService statefulService(){
return new StatefulService();
}
}
}
@Configuration์ ์ ์ฉํ AppConfigํด๋์ค๋
CGLIB๊ฐ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ์ฌ ์ฑ๊ธํค์ผ๋ก ๋ณด์ฅํ๋ค
@Bean
public MemberRepository memberRepository() {
if(memberRepository๊ฐ ์ด๋ฏธ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก๋์ด ์์){
return ์คํ๋ง ์ปจํ
์ด๋์์ ์ฐพ์์ ๋ฐํ;
} else {
๊ธฐ์กด ๋ก์ง์ ํธ์ถํด์ ์์ฑํ๊ณ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก
return ๋ฐํ;
}
}
@ComponentScan
@Component ๊ฐ ๋ถ์ ๋ชจ๋ ํด๋์ค๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก
basePackages : ํ์ํ ์์น๋ถํฐ ํ์ํ๋๋ก ์์ ์์น ์ง์
@SpringBootApplication ์์ @ComponentScan์ด ๋ค์ด์์
@Controller : ์คํ๋ง MVC ์ปจํธ๋กค๋ฌ
@Repository : ์คํ๋ง ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต์ผ๋ก ์ธ์, ๋ฐ์ดํฐ ๊ณ์ธต์ ์์ธ๋ฅผ ์คํ๋ง ์์ธ๋ก ๋ณํ
@Configuration : ์คํ๋ง ์ค์ ์ ๋ณด๋ก ์ธ์, ์คํ๋ง ๋น์ด ์ฑ๊ธํค์ ์ ์งํ๋๋ก ์ถ๊ฐ ์ฒ๋ฆฌ
@Service : ๋น์ฆ๋์ค ๊ณ์ธต ์ธ์ ๋์
์ปดํฌ๋ํธ ์ค์บ ์ ์ธ
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {}
@ComponentScan(
includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
excludeFilters = @Filter(type= FilterType.ANNOTATION, classess = MyExcludeComponent.class)
)
@Autowired
์๋์ผ๋ก ํ์ ์ด ๊ฐ์ ์คํ๋ง ๋น์ ์ฐพ์์ ์ฃผ์
์ฐ์ ์์
1. ํ๋๋ช ๋งคํ
2. @Qualifier ๋ผ๋ฆฌ ๋งค์นญ > ๋น ์ด๋ฆ ๋งค์นญ
3. @Primary : ์ฐ์ ์์ ์ ํ๊ธฐ
์๋๋น ๋ฑ๋ก
-> ์ ๋ฌด ๋ก์ง ๋น : ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ
-> ๊ธฐ์ ์ง์ ๋น : AOP๋ ๊ธฐ์ ์ ์ธ ๋ฌธ์ ์ฒ๋ฆฌํ ๋, ๊ณตํต ๋ก๊ทธ ์ฒ๋ฆฌ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ
- ์ธํฐํ์ด์ค (InitializingBean, DisposableBean)
์์๋ฐ์์ afterPropertiesSet()๋ฉ์๋๋ก ์ด๊ธฐํ ์ง์, destroy()๋ฉ์๋๋ก ์๋ฉธ ์ง์
- ์ค์ ์ ๋ณด์ ์ด๊ธฐํ ๋ฉ์๋, ์ข ๋ฃ ๋ฉ์๋ ์ง์
@Bean์ destroyMethod ์์ฑ์์ close, shutdown ์ด๋ฆ์ ์ข ๋ฃ ๋ฉ์๋ ์ฌ์ฉ
@Bean(initMethod="init", destroyMethod="close")
- @PostConstruct @PreDestroy ์ด๋ ธํ ์ด์ ์ง์
์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์ฉ x
1) ์ฑ๊ธํค : ๊ธฐ๋ณธ ์ค์ฝํ, ์์-์ข ๋ฃ
@Test
void singletonBeanFind() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicatiohnContext(Singleton.class);
SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);
assertThat(singletonBean1).isSameAs(singletonBean2);
ac.close();
}
@Scope("singleton")
static class SingletonBean {
@PostConstruct
public void init(){
System.out.println("init");
}
@PreDestroy
public void destroy(){
System.out.println("destroy");
}
}
2) ํ๋กํ ํ์ : ๋น์ ์์ฑ๊ณผ ์์กด๊ด๊ณ ์ฃผ์ ๊น์ง๋ง ๊ด์ฌ, ๋๋ ๊ด๋ฆฌ x, @PreDistory ๊ฐ์ ์ข ๋ฃ ๋ฉ์๋๊ฐ ํธ์ถ๋์ง ์์
์ฃผ์ ๋ฐ๋ ์์ ์ ๊ฐ๊ฐ ์๋ก์ด ํ๋กํ ํ์ ๋น์ด ์์ฑ๋จ
ํ๋กํ ํ์ ์ค์ฝํ + ์ฑ๊ธํค ๋น๊ณผ ํจ๊ป ์ฌ์ฉ์ Provider๋ก ๋ฌธ์ ํด๊ฒฐ
์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ๋ฐ๋๊ฒ ์๋๋ผ ์ง์ ์์กด๊ด๊ณ ์ฐพ๋ ๊ฒ์ Dependency Lookup(DL)์ด๋ผ๊ณ ํ๋ค
ObjectFactory, ObjectProvider
3) ์น ๊ด๋ จ ์ค์ฝํ : request(์์ฒญ๋ค์ด์ค๊ณ ๋๊ฐ๋๊น์ง), session(์น์ธ์ ), application(์๋ธ๋ฆฟ์ปจํ ์คํธ์ ๊ฐ์ ๋ฒ์)
์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋ ์์ ์ request ์ค์ฝํ ๋น์ ์์ฑ๋์ง ์์ -> ์ค์ ๊ณ ๊ฐ์ ์์ฒญ์ด ๋ค์ด์์ผ ์์ฑ๋จ
๊ทธ๋์, ๋ฏธ๋ฆฌ Proxy ํด๋์ค๋ฅผ ๋ค๋ฅธ ๋น์ ๋ฏธ๋ฆฌ ์ฃผ์ ํจ
@Component
@Scope(value="request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
private String uuid, requestURL;
public void log(String message){
System.out.println(uuid+" "+requestURL+" "+message);
}
@PostConstruct
public void init(){
}
@PreDestroy
public void close() {
}
}
ํ๋ก์
- CGLIB ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ํด๋์ค ์์ ๋ฐ์ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด
- ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ request scope์๋ ๊ด๊ณ ์์
| [ํจํค์ง๋ฐ๋ฐฐํฌ] Jar vs War (0) | 2024.12.21 |
|---|---|
| [Spring] @Transactional (0) | 2024.12.13 |
| [์คํ๋ง] AOP์ @Transactional (0) | 2024.11.27 |
| [์คํ๋ง] ๋์์ฑ ๋ฌธ์ , ThreadLocal (0) | 2024.11.25 |
| [๋ฐ์ดํฐ๋ฒ ์ด์ค]JPQL : N + 1 ๋ฌธ์ , Fetch Join, ์ฃผ์์ฌํญ (0) | 2023.07.11 |