2022. 6. 4. 10:51γBackend/πΏ Spring
μ μ μ€νλ§ μ»¨ν μ΄λκ° λΉμ κ΄λ¦¬νλ λ°©μμ μ§μ΄λ³΄μ.
@Bean μ΄λ Έν μ΄μ μ μ¬μ©νκ±°λ, μ»΄ν¬λνΈ μ€μΊμΌλ‘ μ€νλ§ λΉμ λ±λ‘νλ©΄ μ€νλ§μ λμ κ°μ²΄λ₯Ό μμ±νκ³ μ€νλ§ μ»¨ν μ΄λ λ΄λΆμ λΉ μ μ₯μμ λ±λ‘νλ€. μ΄μ 컨ν μ΄λμ λ±λ‘λ μ€νλ§ λΉμ μ‘°ννμ¬ νμν λ ν΄λΉ λΉμ μ¬μ©νλ€.
μ΄μ ν¬μ€νΈμμ νλ‘μλ₯Ό μ€μ ν λ°©λ²μ μκ°ν΄λ³΄μ.
μ€μ κ°μ²΄λ₯Ό μ€νλ§ λΉμΌλ‘ λ±λ‘νλ κ²μ΄ μλ ProxyFactoryConfigV1 μ²λΌ, λΆκ° κΈ°λ₯μ΄ μλ νλ‘μλ₯Ό μ€μ κ°μ²΄ λμ μ€νλ§ μ»¨ν μ΄λμ λΉμΌλ‘ λ±λ‘ν΄μΌ νλ€. κ·ΈλΌ Component Scan λ°©μμΌλ‘ λΉμ λ±λ‘νλ κ²½μ°μ μ΄λ»κ² νλ‘μ μ€μ μ ν μ μμκΉ? μ΄λ―Έ μ€νλ§ μ»¨ν μ΄λμ λ±λ‘μ΄ λκΈ° λλ¬Έμ νλ‘μλ₯Ό μ€μ κ°μ²΄ λμ λ±λ‘ν μ λ μκ² λλ€.
λ§μ½ μ€μ κ°μ²΄κ° μ€νλ§ λΉμΌλ‘ λ±λ‘λκΈ° μ§μ μ νλ‘μ κ°μ²΄λ‘ λ체ν μ μλ€λ©΄, μ€νλ§ μ»¨ν
μ΄λμ νλ‘μ κ°μ²΄λ₯Ό λμ λ±λ‘ν μ μμ κ²μ΄λ€. μ΄λ₯Ό μν΄ μ°λ¦¬λ λΉ νμ²λ¦¬κΈ°
λΌλ κΈ°μ μ μμλ³΄κ² λ€.
ProxyFactoryConfigV1
@Slf4j
@Configuration
public class ProxyFactoryConfigV1 {
@Bean // λΉ λ§λ€ νλ‘μ ν©ν 리λ₯Ό μμ±ν΄μΌνλ€.
public OrderControllerV1 orderControllerV1(LogTrace logTrace) {
OrderControllerV1 orderController = new OrderControllerV1Impl(orderServiceV1(logTrace));
ProxyFactory factory = new ProxyFactory(orderController);
factory.addAdvisor(getAdvisor(logTrace));
OrderControllerV1 proxy = (OrderControllerV1) factory.getProxy();
log.info("ProxyFactory proxy={}, target={}", proxy.getClass(), orderController.getClass());
return proxy;
}
@Bean
public OrderServiceV1 orderServiceV1(LogTrace logTrace) {
OrderServiceV1 orderService = new OrderServiceV1Impl(orderRepositoryV1(logTrace));
ProxyFactory factory = new ProxyFactory(orderService);
factory.addAdvisor(getAdvisor(logTrace));
OrderServiceV1 proxy = (OrderServiceV1) factory.getProxy();
log.info("ProxyFactory proxy={}, target={}", proxy.getClass(), orderService.getClass());
return proxy;
}
@Bean
public OrderRepositoryV1 orderRepositoryV1(LogTrace logTrace) {
OrderRepositoryV1Impl orderRepository = new OrderRepositoryV1Impl();
ProxyFactory factory = new ProxyFactory(orderRepository);
factory.addAdvisor(getAdvisor(logTrace));
OrderRepositoryV1 proxy = (OrderRepositoryV1) factory.getProxy();
log.info("ProxyFactory proxy={}, target={}", proxy.getClass(), orderRepository.getClass());
return proxy;
}
private Advisor getAdvisor(LogTrace logTrace) {
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("request*", "order*", "save*"); // no-log μ μΈνκΈ° μν¨..?
LogTraceAdvice advice = new LogTraceAdvice(logTrace);
return new DefaultPointcutAdvisor(pointcut, advice);
}
}
λΉ νμ²λ¦¬κΈ° - BeanPostProcessor
λΉ νμ²λ¦¬κΈ°λ μ€νλ§ λΉ μ μ₯μμ λ±λ‘ν λͺ©μ μΌλ‘ μμ±ν κ°μ²΄λ₯Ό λΉ μ μ₯μμ λ±λ‘νκΈ° μ§μ μ μ‘°μνκ³ μΆμ λ μ¬μ©ν μ μλ€. λΉ νμ²λ¦¬κΈ°λ κ°μ²΄λ₯Ό μ‘°μν μ μκ³ , μμ ν λ€λ₯Έ κ°μ²΄λ‘ λ°κΏμΉκΈ° νλ κ²λ κ°λ₯νλ€.
λΉ νμ²λ¦¬κΈ°λ₯Ό ν΅ν λΉ λ±λ‘ κ³Όμ
- μμ± : μ€νλ§ λΉ λμμ΄ λλ κ°μ²΄λ₯Ό μμ±νλ€. (@Bean μ»΄ν¬λνΈ μ€μΊ ν¬ν¨)
- μ λ¬ : μμ±λ κ°μ²΄λ₯Ό λΉ μ μ₯μμ λ±λ‘νκΈ° μ§μ μ λΉ νμ²λ¦¬κΈ°μ λ±λ‘νλ€.
- ν μ²λ¦¬ μμ : λΉ νμ²λ¦¬κΈ°λ μ λ¬λ°μ λΉ κ°μ²΄λ₯Ό μ‘°μνκ±°λ λ€λ₯Έ κ°μ²΄( μλ₯Ό λ€μ΄ νλ‘μ κ°μ²΄ λ± ) λ‘ λ°κΏμΉκΈ° ν μ μλ€.
- λ±λ‘ : λΉ νμ²λ¦¬κΈ°λ λΉμ λ°ννλ€. μ λ¬ λ λΉμ κ·Έλλ‘ λ°ννλ©΄ ν΄λΉ λΉμ΄, λ°κΏμΉκΈ° νλ©΄ λ€λ₯Έ κ°μ²΄κ° λΉ μ μ₯μμ λ±λ‘λλ€.
λΉ νμ²λ¦¬κΈ° μ μ© - μμ μ½λ
public class BeanPostProcessorTest {
@Test
void basicConfig() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(
BeanPostProcessorConfig.class);
// beanA μ΄λ¦μΌλ‘ B κ°μ²΄κ° λΉμΌλ‘ λ±λ‘λλ€.
B b = applicationContext.getBean("beanA", B.class);
b.helloB();
// Aλ λΉμΌλ‘ λ±λ‘λμ§ μλλ€.
Assertions.assertThrows(NoSuchBeanDefinitionException.class,
() -> applicationContext.getBean(A.class));
}
@Slf4j
@Configuration
static class BeanPostProcessorConfig {
@Bean(name = "beanA")
public A a() {
return new A();
}
@Bean // BeanPostProcessor λ₯Ό ꡬνν ν΄λμ€λ₯Ό λΉμΌλ‘ λ±λ‘νλ©΄ μ€νλ§ μ»¨ν
μ΄λκ° μλμΌλ‘ λΉ νμ²λ¦¬κΈ°λ₯Ό μΈμνκ³ λμμν¨λ€.
public AToBPostProcessor helloPostProcessor() {
return new AToBPostProcessor();
}
}
@Slf4j
static class A {
public void helloA() {
log.info("hello A");
}
}
@Slf4j
static class B {
public void helloB() {
log.info("hello B");
}
}
@Slf4j
static class AToBPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
log.info("beanName={} bean={}", beanName, bean);
if (bean instanceof A) {
return new B();
}
return bean;
}
}
}
AToBPostProcessor
- λΉ νμ²λ¦¬κΈ° ν΄λμ€λ‘, μΈν°νμ΄μ€μΈ
BeanPostProcessor
λ₯Ό ꡬννλ©΄, μ€νλ§ μ»¨ν μ΄λκ° μλμΌλ‘ λΉ νμ²λ¦¬κΈ°λ‘ μΈμνκ³ λμνλ€. - ν΄λΉ λΉ νμ²λ¦¬κΈ°λ A κ°μ²΄λ₯Ό B κ°μ²΄λ‘ λ°κΏμΉκΈ° νλ€.
- μ μ½λλ₯Ό μμλλ‘ λΆμν΄λ³΄μ.
μ€ν κ²°κ³Όλ₯Ό νμΈν΄λ³΄λ©΄ μ΅μ’ μ μΌλ‘ "beanA" λΌλ μ€νλ§ λΉ μ΄λ¦μ A κ°μ²΄ λμ B κ°μ²΄κ° λ±λ‘λ κ²μ νμΈν μ μλ€. Aκ°μ²΄λ λΉμΌλ‘ λ±λ‘μ‘°μ°¨ λμ§ μμλ€.
μ€κ° μ 리
λΉ νμ²λ¦¬κΈ°λ λΉμ μ‘°μνκ³ λ³κ²½ν μ μλ ννΉ ν¬μΈνΈλ€.
μΌλ°μ μΌλ‘ μ€νλ§ μ»¨ν μ΄λκ° λ±λ‘νλ, (νΉν μ»΄ν¬λνΈ μ€μΊμ λμμ΄ λλ) μ€νλ§ λΉμ μ€κ°μ μ‘°μν λ°©λ²μ΄ μλλ°, λΉ νμ²λ¦¬κΈ°λ₯Ό μ¬μ©νλ©΄ κ°λ°μκ° λ±λ‘νλ λͺ¨λ λΉμ μ€κ°μ μ‘°μν μ μλ€. μ¦ μ°λ¦¬κ° μνλ, μ€μ λΉ κ°μ²΄(μ»΄ν¬λνΈ μ€μΊμ λμ)λ₯Ό νλ‘μλ‘ κ΅μ²΄νλ κ²λ κ°λ₯νλ€λ μλ―Έλ€.
μ€νλ§μ΄ μ 곡νλ λΉ νμ²λ¦¬κΈ°
μμ λ°©λ²μ μ΄μ©νλ©΄ (BeanPostProcessor λ₯Ό ꡬνν΄ μ€νλ§ Config λ‘ μ§μ λ±λ‘) νλ‘μ μμ±μ λΉ νμ²λ¦¬κΈ°λ₯Ό μ μ©ν μ μμ§λ§, μ€νλ§μ μ΄λ―Έ νλ‘μλ₯Ό μμ±νκΈ° μν λΉ νμ²λ¦¬κΈ°λ₯Ό λ§λ€μ΄ μ 곡νλ€.
μλ νλ‘μ μμ±κΈ° - AutoProxyCreator
μ΄ λΌμ΄λΈλ¬λ¦¬λ₯Ό μΆκ°νλ©΄ aspectJ κ΄λ ¨ λΌμ΄λΈλ¬λ¦¬λ₯Ό λ±λ‘νκ³ , μ€νλ§λΆνΈκ° AOP κ΄λ ¨ ν΄λμ€λ₯Ό μλμΌλ‘ μ€νλ§ λΉμ λ±λ‘νλ€.
implementation 'org.springframework.boot:spring-boot-starter-aop'
μ΄ λΌμ΄λΈλ¬λ¦¬λ₯Ό μΆκ°νλ©΄, AnnotationAwareAspectJAutoProxyCreator
λΌλ λΉ νμ²λ¦¬κΈ°κ° μ€νλ§ λΉμΌλ‘ μλ λ±λ‘λλ€. μ΄λ¦ κ·Έλλ‘ μλμΌλ‘ νλ‘μλ₯Ό μμ±νλ λΉ νμ²λ¦¬κΈ°λ€. (ν΄λΉ λΉ νμ²λ¦¬κΈ°λ μ¬λ¬ λΆλͺ¨ κ΄κ³λ₯Ό κ±°μ³ BeanPostProcessor λ₯Ό μμλ°λλ€.)
μ΄ λΉ νμ²λ¦¬κΈ°λ μ€νλ§ λΉμΌλ‘ λ±λ‘λ Advisorλ₯Ό μ°Ύμ νλ‘μκ° νμν κ³³μ μλμΌλ‘ μ μ©ν΄μ£Όλλ°, Advisor μλ μ΄λ―Έ Pointcut κ³Ό Advice κ° ν¬ν¨λμ΄ μκΈ° λλ¬Έμ κ°λ₯νλ€. μ΄λ₯Ό μ’ λ νμ΄μ μκ°ν΄λ³΄μ.
μλμΌλ‘ νλ‘μλ₯Ό μμ±νλ λΉ νμ²λ¦¬κΈ°?
μ΄λ»κ² νλ©΄ νλ‘μλ₯Ό μλμΌλ‘ μμ±ν μ μμκΉ? νλ‘μ μμ±μ νμν μμλ₯Ό μ°¨λ‘λλ‘ μκ°ν΄λ³΄μ. μ°μ νλ‘μλ₯Ό μ μ©ν λμ κ°μ²΄(target)
κ° νμνλ€. κ·Έ λ€μμ νλ‘μ μμ±μ νμν ProxyFactory
κ°μ²΄κ° νμνκ³ , ProxyFactory κ°μ²΄μ μ μ©ν Advisor
λ νμνλ€.
μ°λ¦¬κ° μλ νλ‘μ μμ±κΈ°λ₯Ό μ¬μ©νλ μ΄μ λ, μ»΄ν¬λνΈ μ€μΊμ λμμ΄ λλ λΉμ νλ‘μλ‘ κ΅μ²΄νκΈ° μν¨μ΄λ―λ‘, λμ κ°μ²΄(target)μ ν΄λΉλλ μμλ μ€λΉκ° λ μνλ€. μ΄μ Advisor κ° νμνλ°, νλ‘μ νΈ μ½λ μ΄λκ°μ Advisor κ° μ‘΄μ¬νλ©΄, <code> κ° μλμΌλ‘ μ΄λ₯Ό μ°Ύμ νλ‘μ ν©ν 리μ μ μ©ν΄μ€λ€κ³ λ³Ό μ μλ€.
μλ νλ‘μ μμ±κΈ° μλ κ³Όμ
- μμ± : μ€νλ§μ΄ μ€νλ§ λΉ λμμ΄ λλ κ°μ²΄λ₯Ό μμ±νλ€.
- μ λ¬ : μμ±λ κ°μ²΄λ₯Ό μ€νλ§ λΉμΌλ‘ λ±λ‘νκΈ° μ μ λΉ νμ²λ¦¬κΈ°μ μ λ¬νλ€.
- λͺ¨λ Advisor μ‘°ν :
μλ νλ‘μ μμ±κΈ° - λΉ νμ²λ¦¬κΈ°
λ μ€νλ§ μ»¨ν μ΄λμμ λͺ¨λAdvisor
λ₯Ό μ‘°ννλ€. - νλ‘μ μ μ© λμ μ²΄ν¬ : μ‘°νν Advisor μ ν¬μΈνΈμ»·μ μ¬μ©ν΄ νκ² κ°μ²΄κ° νλ‘μ μ μ© λμμΈμ§ νλ¨νλ€. ν΄λΉ κ°μ²΄μ λͺ¨λ λ©μλλ₯Ό ν¬μΈνΈμ»·μ νλνλ 맀μΉν΄λ³Έλ€. νλλΌλ 쑰건μ λ§μ‘±νλ©΄ νλ‘μ μ μ© λμμ΄ λΌ νλ‘μ κ°μ²΄κ° μμ±λλ€. μ¦ 10κ°μ λ©μλλ₯Ό κ°μ§ κ°μ²΄μμ ν¬μΈνΈμ»·μ 맀μΉλλ λ©μλκ° νλ λΏμΌμ§λΌλ νλ‘μ μ μ© λμμ΄ λλ κ²μ΄λ€.
- νλ‘μ μμ± : νλ‘μ μ μ© λμμ΄λ©΄ νλ‘μ κ°μ²΄λ₯Ό μμ±ν΄ μ€νλ§ μ»¨ν μ΄λμ λ±λ‘νλ€. κ·Έλ μ§ μλ€λ©΄ μλ³Έ κ°μ²΄λ₯Ό μ€νλ§ μ»¨ν μ΄λμ κ·Έλλ‘ λ±λ‘νλ€.
- λΉ λ±λ‘ : λ°νλ κ°μ²΄λ μ€νλ§ λΉμΌλ‘ λ±λ‘νλ€.
μ€μ μ μ© μ½λ - AspectJExpressionPointcut
λμ λκ² μ½λλμ΄ μ€μ΄λ κ²μ λ³Ό μ μλλ°, λΉ νμ²λ¦¬κΈ° μ체(AnnotationAwareAspectJAutoProxyCreator
)κ° μ€νλ§μ μν΄ μλμΌλ‘ λ±λ‘λκΈ° λλ¬Έμ΄λ€.
@Configuration
@Import({AppV1Config.class, AppV2Config.class})
public class AutoProxyConfig {
@Bean
public Advisor advisor(LogTrace logTrace) {
//pointcut
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* hello.proxy.app..*(..))
&& !execution(* hello.proxy.app..noLog(..))");
//advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);
return new DefaultPointcutAdvisor(pointcut, advice);
}
}
νλ‘μλ νλλ§ μμ±λλ€.
μ€νλ§λΉμ΄ Advisor1, Advisor2 κ° μ 곡νλ ν¬μΈνΈμ»·μ 쑰건μ λͺ¨λ λ§μ‘±νλ©΄ νλ‘μ μλ μμ±κΈ°λ νλ‘μλ₯Ό λͺκ° μμ±ν κΉ? ν¬μΈνΈμ»· 쑰건μ λ§μ‘±νλ κ°μ²΄λ§λ€ νλ‘μλ₯Ό μμ±ν κΉ? κ·Έλ μ§ μλ€. νλ‘μ μλ μμ±κΈ°λ νλ‘μλ₯Ό νλλ§ μμ±νλ€. μλνλ©΄ νλ‘μ ν©ν λ¦¬κ° μμ±νλ νλ‘μλ λ΄λΆμ μ¬λ¬ advisor λ₯Ό ν¬ν¨ν μ μκΈ° λλ¬Έμ΄λ€. λ°λΌμ νλ‘μλ₯Ό μ¬λ¬ κ° μμ±ν΄μ λΉμ©μ λλΉν μ΄μ κ° μλ€.
μ¦, Proxy λ νλλ§ μμ±λ λΏμ΄κ³ μ¬λ¬ μ΄λλ°μ΄μ κ° λ€μ΄κ° λΏμ΄λ€.
μ 리
λΉ νμ²λ¦¬κΈ°λ BeanPostProcessor μΈν°νμ΄μ€λ₯Ό ꡬννμ¬, μ€νλ§ μ»¨ν μ΄λμ λ±λ‘λκΈ° μ§μ μ λΉμ μ‘°μν μ μλ€. μ΄λ κ² λΉ νμ²λ¦¬κΈ°λ₯Ό μ¬μ©νλ©΄ μ»΄ν¬λνΈ μ€μΊμΌλ‘ 컨ν μ΄λμ μλμΌλ‘ λ±λ‘λλ λΉμ λν΄μλ νλ‘μ κ°μ²΄λ₯Ό μμ±ν μ μλ€.
λν AutoProxyCreator
λ₯Ό μ¬μ©νλ©΄, μ§μ BeanPostProcessor λ₯Ό ꡬνκ³Όμ μ μλ΅νκ³ , νΈλ¦¬νκ² νλ‘μ μμ±κΈ°λ₯Ό λ§λ€ μ μλ€. κ°λ°μλ Advisor λ§ μ€λΉνλ©΄ νλ‘μλ₯Ό μμ½κ² μμ±ν μ μκ² λλ€.
μ½λ λ° μλ£ μΆμ²
'Backend > πΏ Spring' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[JPA] API κ°λ° - μ§μ°λ‘λ©κ³Ό μ±λ₯ μ΅μ ν (feat.Fetch μ‘°μΈ) (0) | 2022.06.16 |
---|---|
[Spring] @Aspect μ AOP νΊμ보기 (0) | 2022.06.05 |
[Spring] Pointcut, Advise, Advisor κΈ°λ³Έ κ°λ μ μμ보μ (0) | 2022.06.03 |
[Spring] ProxyFactory (0) | 2022.06.03 |
[Spring] λμ νλ‘μ κΈ°μ (3) - CGLIB (0) | 2022.06.02 |