๐ AOP & DI/IoC Integration
๊ฐ์โ
์ด ๋ฌธ์๋ Sprout Framework์์ AOP(Aspect-Oriented Programming)๊ฐ DI/IoC ์ปจํ ์ด๋์ ์ด๋ป๊ฒ ํตํฉ๋์ด ์๋ ํ๋ก์ ์์ฑ์ ์ํํ๋์ง์ ๋ํ ์ฌ์ธต์ ์ธ ๊ธฐ์ ๋ถ์์ ์ ๊ณตํฉ๋๋ค. ์ธํ๋ผ ๋น์ ์ด๊ธฐํ ์์๋ถํฐ CGLIB ๊ธฐ๋ฐ ํ๋ก์ ์์ฑ, ๊ทธ๋ฆฌ๊ณ ๋ฉ์๋ ์ธํฐ์ ์ ์ฒด์ธ๊น์ง์ ์ ๊ณผ์ ์ ์์ธํ ๋ถ์ํ์ฌ Sprout AOP์ ์์ ํ ์๋ ๋ฉ์ปค๋์ฆ์ ์ดํดํ ์ ์๋๋ก ํฉ๋๋ค.
์ ์ฒด ์ํคํ ์ฒ ๊ฐ์โ
AOP-DI ํตํฉ ํ๋ฆ๋โ
์ ํ๋ฆฌ์ผ์ด์
์์
โ
SproutApplicationContext.refresh()
โ
1. ๋น ์ ์ ์ค์บ (scanBeanDefinitions)
โโโ @Component, @Service, @Repository ์ค์บ
โโโ @Aspect ํด๋์ค ์ค์บ
โโโ InfrastructureBean vs ApplicationBean ๋ถ๋ฅ
โ
2. ์ธํ๋ผ ๋น ์ด๊ธฐํ (instantiateInfrastructureBeans)
โโโ AdvisorRegistry, AdviceFactory, ProxyFactory ์์ฑ
โโโ AspectPostProcessor ์์ฑ ๋ฐ ๋ฑ๋ก
โโโ PostInfrastructureInitializer ์คํ
โ
3. AopPostInfrastructureInitializer ์คํ
โโโ @Aspect ํด๋์ค ์ค์บ
โโโ Advisor ์์ฑ ๋ฐ ๋ ์ง์คํธ๋ฆฌ ๋ฑ๋ก
โโโ AspectPostProcessor ์ด๊ธฐํ
โ
4. BeanPostProcessor ๋ฑ๋ก (registerBeanPostProcessors)
โโโ AspectPostProcessor๋ฅผ BeanPostProcessor๋ก ๋ฑ๋ก
โ
5. ์ ํ๋ฆฌ์ผ์ด์
๋น ์ด๊ธฐํ (instantiateAllSingletons)
โโโ ๋น ์์ฑ ์ BeanPostProcessor ์ฒด์ธ ์คํ
โโโ AspectPostProcessor.postProcessAfterInitialization ํธ์ถ
โโโ ํ๋ก์ ํ์์ฑ ํ๋จ ๋ฐ CGLIB ํ๋ก์ ์์ฑ
โโโ BeanMethodInterceptor๋ก ๋ฉ์๋ ์ธํฐ์
์
์ค์
ํต์ฌ ์ค๊ณ ์์นโ
- ์ธํ๋ผ ์ฐ์ ์ด๊ธฐํ: AOP ๊ด๋ จ ์ธํ๋ผ ๋น๋ค์ด ์ ํ๋ฆฌ์ผ์ด์ ๋น๋ณด๋ค ๋จผ์ ์ด๊ธฐํ
- PostProcessor ํจํด: BeanPostProcessor๋ฅผ ํตํ ํฌ๋ช ํ ํ๋ก์ ์์ฑ
- CGLIB ๊ธฐ๋ฐ ํ๋ก์: ์ธํฐํ์ด์ค ์์ด๋ ํ๋ก์ ์์ฑ ๊ฐ๋ฅ
- ์ฒด์ธ ์ค๋ธ ๋ฆฌ์คํ์๋น๋ฆฌํฐ: ์ฌ๋ฌ ์ด๋๋ฐ์ด์ค์ ์์ฐจ์ ์คํ
์ธํ๋ผ ๋น ์ด๊ธฐํ ๋ฉ์ปค๋์ฆโ
1. SproutApplicationContext์ ์ด๊ธฐํ ์ ๋ตโ
๋จ๊ณ๋ณ ์ด๊ธฐํ ๊ณผ์
@Override
public void refresh() throws Exception {
scanBeanDefinitions(); // 1. ๋น ์ ์ ์ค์บ
instantiateInfrastructureBeans(); // 2. ์ธํ๋ผ ๋น ์ด๊ธฐํ (AOP ํฌํจ)
instantiateAllSingletons(); // 3. ์ ํ๋ฆฌ์ผ์ด์
๋น ์ด๊ธฐํ
// 4. ์ปจํ
์คํธ ํ์ฒ๋ฆฌ
List<ContextInitializer> contextInitializers = getAllBeans(ContextInitializer.class);
for (ContextInitializer initializer : contextInitializers) {
initializer.initializeAfterRefresh(this);
}
}
2. ๋น ๋ถ๋ฅ ์ ๋ต: ์ธํ๋ผ vs ์ ํ๋ฆฌ์ผ์ด์ โ
์๋ ๋ถ๋ฅ ์๊ณ ๋ฆฌ์ฆ
private void scanBeanDefinitions() throws NoSuchMethodException {
// ๋ชจ๋ ๋น ์ ์ ์ค์บ
Collection<BeanDefinition> allDefs = scanner.scan(configBuilder,
Component.class, Controller.class, Service.class, Repository.class,
Configuration.class, Aspect.class, ControllerAdvice.class, WebSocketHandler.class
);
// ์ธํ๋ผ ๋น ๋ถ๋ฅ (BeanPostProcessor + InfrastructureBean)
List<BeanDefinition> infraDefs = new ArrayList<>(allDefs.stream()
.filter(bd -> BeanPostProcessor.class.isAssignableFrom(bd.getType()) ||
InfrastructureBean.class.isAssignableFrom(bd.getType()))
.toList());
// ์ ํ๋ฆฌ์ผ์ด์
๋น ๋ถ๋ฅ (๋๋จธ์ง)
List<BeanDefinition> appDefs = new ArrayList<>(allDefs);
appDefs.removeAll(infraDefs);
this.infraDefs = infraDefs;
this.appDefs = appDefs;
}
๋ถ๋ฅ ๊ธฐ์ค
- ์ธํ๋ผ ๋น:
BeanPostProcessor
๊ตฌํ์ฒด +InfrastructureBean
๊ตฌํ์ฒด - ์ ํ๋ฆฌ์ผ์ด์ ๋น: ๋๋จธ์ง ๋ชจ๋ ๋น (๋น์ฆ๋์ค ๋ก์ง ๋น๋ค)
๋ถ๋ฅ์ ์ค์์ฑ
- ์์ ๋ณด์ฅ: AOP ์ธํ๋ผ๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ๋น๋ณด๋ค ๋จผ์ ์ค๋น๋จ
- ์์กด์ฑ ํด๊ฒฐ: PostProcessor๋ค์ด ์ ํ๋ฆฌ์ผ์ด์ ๋น ์์ฑ ์์ ์ ์ฌ์ฉ ๊ฐ๋ฅ
- ์ด๊ธฐํ ๋ถ๋ฆฌ: ๊ฐ ๊ทธ๋ฃน๋ณ๋ก ๋ ๋ฆฝ์ ์ธ ์ด๊ธฐํ ์ ๋ต ์ ์ฉ