Category: Spring

0

Spring AOP - 적용 방식

목차 Spring AOP - Advice 종류 Spring AOP - 트랜잭션 순서 Spring AOP - Pointcut 참조 Spring AOP - 어드바이스 추가 Spring AOP - Pointcut 분리 Spring AOP - @Aspect Spring AOP - 용어 정리 Spring AOP - 적용 방식 Spring AOP - Aspect 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. 횡단 관심 사항횡단 관심 사항(Cross-cutting Concern)은 애플리케이션 전반에서 공통적으로 사용되는 기능입니다. 즉, 여러 모듈에서 공통으로 사용되는 기능으로서, 여러 코드에 걸쳐 분산되어 있을 수 있습니다. 이러한 횡단 관심 사항은 핵심 비즈니스 로직과 분리되어 있기 때문에 애플리케이션의 유지 보수성과 확장성에 영향을 미칩니다. 횡단 관심 사항의 예로는 로깅, 보안, 트랜잭션 처리 등이 있습니다. 예를 들어, 여러 모듈에서 공통적으로 로그를 출력해야 한다면, 모든 코드에 로그를 출력하는 코드를 추가해야 합니다. 하지만 이러한 방식은 유지 보수성이 떨어지고 코드 중복이 발생합니다. 이를 해결하기 위해 로그 출력과 같은 공통 기능을 모듈화하고 재사용 가능한 코드로 만들어주는 것이 바로 AOP의 역할입니다. AOP를 사용하면 핵심 로직 코드를 수정하지 않고도 횡단 관심 사항을 처리할 수 있습니다. 즉, 공통 기능을 모듈화하여 애플리케이션 전반에서 쉽게 사용할 수 있게 됩니다. 이를 통해 애플리케이션의 유지 보수성과 확장성이 향상되며, 코드의 가독성도 높아지는 등의 장점을 가집니다. Spring AOP AOP 를 사용하면 핵심기능 과 부가기능 이 코드상 완전히 분리 된다.

0

Spring AOP - Aspect

목차 Spring AOP - Advice 종류 Spring AOP - 트랜잭션 순서 Spring AOP - Pointcut 참조 Spring AOP - 어드바이스 추가 Spring AOP - Pointcut 분리 Spring AOP - @Aspect Spring AOP - 용어 정리 Spring AOP - 적용 방식 Spring AOP - Aspect 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. Aspect 부가 기능 과 부가 기능 을 어디에 적용할지 적용할지를 정의 Aspect 는 애플리케이션 전반에서 공통적으로 사용되는 기능들을 모듈화하고, 재사용 가능한 코드로 만들어주는 모듈화 기능입니다. Aspect 를 사용한 프로그래밍을 관점 지향 프로그래밍 AOP (Aspect-Oriented Programming) 이라 합니다. AOP 를 적용함으로써 핵심 로직 코드를 수정하지 않고도 횡단 관심 사항(cross-cutting concern) 을 처리할 수 있습니다. Spring에서는 Aspect를 정의하기 위해 @Aspect 어노테이션을 사용하며, Aspect를 구현하기 위해 @Before, @After, @Around 등의 Advice 어노테이션을 사용합니다. 이러한 어노테이션을 사용하여 Advice를 구현하고, @Pointcut 어노테이션을 사용하여 Pointcut을 정의합니다. Aspect를 구현하여 애플리케이션 전반에 걸쳐 공통 기능을 모듈화하고 재사용 가능한 코드로 만들 수 있습니다. 이를 통해 애플리케이션의 유지 보수성과 확장성을 향상시킬 수 있습니다.

0

BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor - AutoProxyCreator BeanPostProcessor 를 이용한 프록시 객체 생성 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. 여러개의 Advisor 적용빈 후처리기에서 프록시 객체 생성시 여러개의 포인트컷에 해당되는 객체가 있습니다. 객체가 여러개의 포인트 컷에 해당되더라도 프록시 객체는 한개만 생성됩니다. Advisor1 의 포인트 컷만 만족 프록시 객체 1개 생성, advisor1 만 포함 Advisor1, Advisor2 의 포인트 컷 모두 만족 프록시 객체 1개 생성, advisor1, advisor2 모두 포함 Advisor1, Advisor2 의 포인트 컷 모두 만족하지 않음 프록시 객체를 생성하지 않음 하나의 프록시에 여러개의 Advisor하나의 프록시 객체에 여러개의 Advisor 를 포함하는 형태로 프록시 객체가 생성됩니다.

0

BeanPostProcessor - AutoProxyCreator

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor - AutoProxyCreator BeanPostProcessor 를 이용한 프록시 객체 생성 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. 라이브러리 추가implementation 'org.springframework.boot:spring-boot-starter-aop' //추가 자동 프록시 생성기 - AutoProxyCreator 스프링에서 AnnotationAwareAspectJAutoProxyCreator 라는 빈 후처리기가 등록됩니다. AnnotationAwareAspectJAutoProxyCreator 는 스프링 빈으로 등록된 Advisor 를 자동으로 찾아 프록시 객체를 생성해줍니다. 또한, @AspectJ 와 관련된 AOP 기능도 자동으로 찾아서 처리해줍니다. Bean 으로 등록하기 위한 객체를 생성 후 빈 후처리기에 전달합니다. 빈 후처리기 중 자동 프록시 생성 빈 후처리기에서 모든 Advisor 를 조회합니다. Advisor 에 포함된 Pointcut 을 사용해 프록시를 적용할 대상인지 확인합니다. 이때 객체의 패키지정보, 클래스 정보 와 해당 객체내 모든 메소드를 하나하나씩 매칭합니다.

0

BeanPostProcessor 를 이용한 프록시 객체 생성

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor - AutoProxyCreator BeanPostProcessor 를 이용한 프록시 객체 생성 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory / 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. https://www.baeldung.com/spring-beanpostprocessor BeanPostProcessor 를 이용한 프록시 객체 생성빈 후처리기를 이용해 Bean 생성시점에 프록시 객체를 생성할 수 있습니다. 다만, 스프링에 등록되는 모든 빈들은 빈 후처리기로 넘어옵니다. 그래서 모든 Bean 에 대해 BeanPostProcessor 로직이 수행되므로 어떤 Bean 을 Proxy Bean 으로 생성할지에 대한 기준이 필요하다. BeanPostProcessor 를 이용한 프록시 객체 생성 과정빈 후처리기를 이용해 프록시 객체를 생성하는 방법은 4가지 단계가 있습니다. 첫번째는 Bean 대상이 되는 객체를 생성합니다. 두번째는 생성된 객체를 빈 후처리기에 전달합니다. 셋번째는 빈 후처리기에서 전달 받은 객체를 이용해 프록시 객체를 생성 후 반환합니다. 네번째 빈 후처리기에서 반환된 프록시 객체를 Bean 저장소에 등록합니다.

0

BeanPostProcessor

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor - AutoProxyCreator BeanPostProcessor 를 이용한 프록시 객체 생성 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. https://www.baeldung.com/spring-beanpostprocessor BeanPostProcessor Spring Bean 을 등록하는 시점에 특정 로직을 수행하기 위해 사용하는 hook (LifeCycle 에 간섭할 수 있다.)Spring Bean 전체에 공통 로직을 수행할 때 사용하면 유용하다 BeanPostProcessor 는 Bean 의 생성과 초기화를 제어하는 인터페이스입니다. 이 인터페이스를 사용하면 스프링 빈이 생성되고 초기화되는 과정에서 추가적인 작업을 수행할 수 있습니다. 예를 들어, 스프링 빈의 필드를 초기화하거나, 빈 객체의 프록시를 생성하는 등의 작업을 수행할 수 있습니다. BeanPostProcessor 인터페이스

0

Spring 핵심원리 고급편 - ProxyFactory 적용

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. 인터페이스 객체에 프록시 팩토리 적용스프링에서 제공하는 MethodInterceptor 인터페이스를 이용해 import org.aopalliance.intercept.MethodInterceptor;public class LogTraceAdvice implements MethodInterceptor { private final LogTrace logTrace; public LogTraceAdvice(LogTrace logTrace) { this.logTrace = logTrace; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { TraceStatus status = null; try { Method method = invocation.getMethod(); String message = method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()"; status = logTrace.begin(message); // 로직 호출 Object result = invocation.proceed(); logTrace.end(status); return result; } catch (Exception ex) { logTrace.exception(status, ex); throw ex; } }} @Slf4j@Configurationpublic class ProxyFactoryConfigV1 { @Bean public OrderControllerV1 orderControllerV1(LogTrace logTrace){ OrderControllerV1 orderController = new OrderControllerV1Impl(orderServiceV1(logTrace)); // OrderControllerV1 객체를 Proxy 객체로 생성한다. ProxyFactory factory = new ProxyFactory(orderController); factory.addAdvisor(getAdvisor(logTrace)); // Advisor 를 적용한다. OrderControllerV1 proxy = (OrderControllerV1) factory.getProxy(); log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderController); return proxy; } @Bean public OrderServiceV1 orderServiceV1(LogTrace logTrace){ OrderServiceV1Impl orderService = new OrderServiceV1Impl(orderRepositoryV1(logTrace)); // OrderServiceV1Impl 객체를 Proxy 객체로 생성한다. ProxyFactory factory = new ProxyFactory(orderService); factory.addAdvisor(getAdvisor(logTrace)); // Advisor 를 적용한다. OrderServiceV1 proxy = (OrderServiceV1) factory.getProxy(); log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderService); return proxy; } @Bean public OrderRepositoryV1 orderRepositoryV1(LogTrace logTrace){ OrderRepositoryV1Impl orderRepository = new OrderRepositoryV1Impl(); // OrderRepositoryV1Impl 객체를 Proxy 객체로 생성한다. ProxyFactory factory = new ProxyFactory(orderRepository); factory.addAdvisor(getAdvisor(logTrace)); // Advisor 를 적용한다. OrderRepositoryV1 proxy = (OrderRepositoryV1) factory.getProxy(); log.info("ProxyFactory proxy = {}, target = {}", proxy.getClass(), orderRepository); return proxy; } private Advisor getAdvisor(LogTrace logTrace) { // Point Cut NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); pointcut.setMappedNames("request*", "order*", "save*"); // advice LogTraceAdvice advice = new LogTraceAdvice(logTrace); // Pointcut과 Advice 를 이용해 Advisor 객체를 만들어준다. return new DefaultPointcutAdvisor(pointcut, advice); }} 애플리케이션 로딩 시점에서 해당 Bean 이 Loading 되는 것을 확인할 수 있다. 2021-12-05 01:09:21.671 INFO 64531 --- [ main] h.p.c.v.ProxyFactoryConfigV1 : ProxyFactory proxy = class com.sun.proxy.$Proxy50, target = hello.proxy.app.v1.OrderRepositoryV1Impl@5555ffcf2021-12-05 01:09:21.673 INFO 64531 --- [ main] h.p.c.v.ProxyFactoryConfigV1 : ProxyFactory proxy = class com.sun.proxy.$Proxy52, target = hello.proxy.app.v1.OrderServiceV1Impl@5a2fa51f2021-12-05 01:09:21.674 INFO 64531 --- [ main] h.p.c.v.ProxyFactoryConfigV1 : ProxyFactory proxy = class com.sun.proxy.$Proxy53, target = hello.proxy.app.v1.OrderControllerV1Impl@6ecdbab8

0

Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. 여러 Advisor 와 함께 적용 하나의 Target 에 여러 Advisor 를 적용한다. // 여러개의 프록시 객체// client -> proxy2(advisor2) -> proxy1(advisor1) -> target// Proxy 1 생성ServiceInterface target = new ServiceImpl();ProxyFactory proxyFactory = new ProxyFactory(target);// Advisor 인터페이스의 가장 일반적인 구현체DefaultPointcutAdvisor advisor1 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice1());// ProxyFactory 에 적용할 Advisor 를 지정한다.proxyFactory.addAdvisor(advisor1);ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();/////////////////////////////////////////////////////////////////////////////////////////////// Proxy 2 생성 (taget -> proxy 1 입력)ProxyFactory proxyFactory2 = new ProxyFactory(proxy);// Advisor 인터페이스의 가장 일반적인 구현체DefaultPointcutAdvisor advisor2 = new DefaultPointcutAdvisor(Pointcut.TRUE, new Advice2());// ProxyFactory 에 적용할 Advisor 를 지정한다.proxyFactory2.addAdvisor(advisor2);ServiceInterface proxy2 = (ServiceInterface) proxyFactory2.getProxy();proxy2.save(); 00:36:05.734 [Test worker] INFO hello.proxy.advisor.MultiAdvisorTest$Advice2 - advice2 호출00:36:05.737 [Test worker] INFO hello.proxy.advisor.MultiAdvisorTest$Advice1 - advice1 호출00:36:05.737 [Test worker] INFO hello.proxy.common.service.ServiceImpl - save 호출 하나의 프록시로 여러개의 Advisor 적용 위에서는 여러 Advisor 를 적용하기 위해서는 여러개의 프록시를 생성 해야 한다는 문제점이 있다.스프링 AOP 에서는 하나의 프록시만 생성 하고 여러개의 Advisor 를 적용 할 수 있도록 지원한다.

0

Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. save 메서드는 어드바이스 로직을 적용하지만, find 메서드에서는 어드바이스 로직을 적용하지 않도록 설정하기 Spring 에서 제공하는 Pointcut 가장 많이 사용하는 Pointcut 구현체는 AspectJExpressionPointcut 다. 클래스 설명 NameMatchMethodPointcut 메서드 이름을 기반으로 매칭한다. 내부적으로 PatternMatchUtils 을 사용한다. JdkRegexpMethodPointcut JDK 정규 표현식을 기반으로 포인트 컷을 한다. AnnotationMatchingPointcut 애노테이션으로 매칭한다. AspectJExpressionPointcut aspectJ 표현식으로 매칭한다. ServiceInterface target = new ServiceImpl();ProxyFactory proxyFactory = new ProxyFactory(target);// Spring 에서 제공하는 PointcutNameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();pointcut.setMappedNames("save");// Advisor 인터페이스의 가장 일반적인 구현체DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, new TimeAdvice());// ProxyFactory 에 적용할 Advisor 를 지정한다.proxyFactory.addAdvisor(advisor);ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();proxy.save();proxy.find(); 00:14:12.347 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 실행00:14:12.349 [Test worker] INFO hello.proxy.common.service.ServiceImpl - save 호출00:14:12.349 [Test worker] INFO hello.proxy.common.advice.TimeAdvice - TimeProxy 종료 resultTime = 000:14:12.351 [Test worker] INFO hello.proxy.common.service.ServiceImpl - find 호출

0

Spring 핵심원리 고급편 - Pointcut 만들기

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. Pointcut 인터페이스 Pointcut 은 getClassFilter 메서드와 getMethodMatcher 메서드를 이용해 필터링 을 진행한다.둘다 TRUE 를 반환해야 Advice 를 적용할 수 있다 getClassFilter : Class 조건으로 Filter 하는 메서드 .getMethodMatcher : Method 조건으로 Filter 하는 메서드 public interface Pointcut { // 클래스 조건으로 필터링 ClassFilter getClassFilter(); // 메서드 조건으로 필터링 MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE;} Pointcut 적용하기 save 메서드는 Advice 로직을 적용하지만, find 메서드에서는 Advice 로직을 적용하지 않도록 설정하기

0

Spring 핵심원리 고급편 - Advisor

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. Advisor Advisor는 Spring AOP에서 Advice, Pointcut, Advisor의 개념을 쉽게 사용할 수 있도록 제공합니다. Advice 는 메소드를 실행하기 전, 후, 혹은 예외가 발생했을 때 실행되는 부가 기능을 말하며, Pointcut 은 Advice가 적용될 메소드를 선택하는 기준입니다. Advisor 는 Advice 와 Pointcut 을 결합한 것으로, 어떤 메소드에 어떤 Advice 를 적용할지를 결정합니다. PointCut (포인트 컷) 어디에 부가 기능을 적용할지 적용하지 않을지 판단하는 필터링 로직 클래스 이름과 메서드 이름을 이용해 필터링 한다. Advice (어드바이스) 프록시가 호출하는 부가 기능 Advisor (어드바이저) 단순하게 하나의 포인트 컷 과 하나의 어드바이스 를 갖고 있는 것 DefaultPointcutAdvisor

0

Spring 핵심원리 고급편 - CGLIB

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 참고 https://www.baeldung.com/cglib Dynamic Proxy 의 한계와 CGLIBDynamic Proxy 의 경우 인터페이스를 구현한 클래스에 대해서만 프록시 객체를 생성할 수 있습니다. 그렇다면 인터페이스가 없는 클래스의 경우 프록시 생성을 못하냐? 정답은 아닙니다. 자바에서는 인터페이스를 구현하지 않은 클래스에 대해서도 프록시 객체를 생성할 수 있도록 CGLIB 를 제공합니다. 차이점은 Dynamic Proxy 는 인터페이스 구현을 통해 프록시 객체를 생성하지만 CGLIB 는 상속 을 통해 프록시 객체를 생성한다는 것입니다. CGLIB 란? CGLIB 는 Code Generation Library의 약자로 런타임 시 Java 바이트 코드 를 조작해 동적으로 클래스를 생성하는 라이브러리다. JDK Dynamic 프록시와는 다르게 구체 클래스 만 갖고도 동적으로 Proxy 를 생성할 수 있다. CGLIB은 자바의 리플렉션(Reflection) API 와 바이트코드 조작(Bytecode Manipulation) 기술을 이용하여 클래스의 상속 구조를 이용해서 프록시 객체를 생성합니다. 이 과정에서 바이트코드를 조작하므로, JVM의 클래스 로딩 과정에서 원본 클래스의 바이트코드를 변경할 수 있습니다.

0

Spring 핵심원리 고급편 - MethodInterceptor

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. MethodInterceptor - 부가기능 구현Spring 에서는 프록시 객체에 부가기능을 적용하기 위해 MethodInterceptor 인터페이스를 제공합니다. MethodInterceptor 인터페이스 구현을 통해 프록시 객체에 적용될 부가기능을 생성할 수 있습니다. MethodInterceptor 인터페이스 내 invoke 메소드 인자 MethodInvocation 객체에는 다음 메서드를 호출하는 방법, 현재 프록시 객체 인스턴스, args, 메서드 정보등이 표함돼 있다. CGLIB 에서 제공하는 MethodInterceptor 와 이름이 비슷하므로 구현시 주의할 필요가 있습니다. package org.aopalliance.intercept;public interface MethodInterceptor extends Interceptor { Object invoke(MethodInvocation invocation) throws Throwable; }

0

Spring 핵심원리 고급편 - ProxyFactory

목차 BeanPostProcessor - 하나의 프록시에 여러개의 Advisor 적용 BeanPostProcessor Spring 핵심원리 고급편 - ProxyFactory 적용 Spring 핵심원리 고급편 - 여러 Advisor 와 함께 적용 Spring 핵심원리 고급편 - Spring 에서 제공하는 Pointcut Spring 핵심원리 고급편 - Pointcut 만들기 Spring 핵심원리 고급편 - Advisor Spring 핵심원리 고급편 - MethodInterceptor Spring 핵심원리 고급편 - ProxyFactory 참고본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다. Spring 에서의 ProxyFactory Spring 에서는 프록시 객체를 생성하기 위해 ProxyFactory 를 제공합니다. Spring에서 ProxyFactory 는 프록시 객체를 생성하는 팩토리입니다. ProxyFactory 는 인터페이스가 있을 때는 JDK 동적 프록시 를 사용해 프록시 객체를 생성하고 인터페이스가 없을 경우에는 CGLIB 를 사용해 프록시 객체를 생성합니다. Advice Advice 는 프록시에 적용하는 부가 기능 로직 이다.JDK 동적 프록시 가 제공하는 InvocationHandler 와 CGLIB 가 제공하는 MethodInterceptor 의 개념과 유사하다.

0

Spring 핵심원리 고급편 - Dynamic Proxy 2

목차 Spring 핵심원리 고급편 - CGLIB Spring 핵심원리 고급편 - Dynamic Proxy 2 Spring 핵심원리 고급편 - Dynamic Proxy 1 Spring 핵심원리 고급편 - 리플렉션 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 적용 2 Spring 핵심원리 고급편 - 구체 클래스 기반 프록시 Spring 핵심원리 고급편 - 인터페이스 프록시 1 Spring 핵심원리 고급편 - Decorator Pattern 2 Spring 핵심원리 고급편 - Decorator Pattern 1 Spring 핵심원리 고급편 - Proxy 패턴 컴포넌트 스캔으로 자동 빈 등록 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스 없는 없는 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 인터페이스와 구체 클래스 Spring 핵심원리 고급편 - Proxy 패턴 Spring 핵심원리 고급편 - Strategy 패턴 Spring 핵심원리 고급편 - Template Method 패턴 public class LogTraceBasicHandler implements InvocationHandler { private final Object target; private final LogTrace logTrace; public LogTraceBasicHandler(Object target, LogTrace logTrace) { this.target = target; this.logTrace = logTrace; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { TraceStatus status = null; try { String message = method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()"; status = logTrace.begin(message); // 로직 호출 method.invoke(target, args); logTrace.end(status); return result; } catch (Exception ex) { logTrace.exception(status, ex); throw ex; } }} @Configurationpublic class DynamicBasicProxyConfig { @Bean public OrderControllerV1 orderControllerV1(LogTrace logTrace){ OrderControllerV1 orderControllerV1 = new OrderControllerV1Impl(orderServiceV1(logTrace)); // Proxy 객체 생성 OrderControllerV1 proxy = (OrderControllerV1) Proxy .newProxyInstance( OrderControllerV1.class.getClassLoader(), new Class[]{OrderControllerV1.class}, new LogTraceBasicHandler(orderControllerV1, logTrace)); return proxy; } @Bean public OrderServiceV1 orderServiceV1(LogTrace logTrace){ OrderServiceV1 orderServiceV1 = new OrderServiceV1Impl(orderRepositoryV1(logTrace)); // Proxy 객체 생성 OrderServiceV1 proxy = (OrderServiceV1) Proxy .newProxyInstance( OrderServiceV1.class.getClassLoader(), new Class[]{OrderServiceV1.class}, new LogTraceBasicHandler(orderServiceV1, logTrace)); return proxy; } @Bean public OrderRepositoryV1 orderRepositoryV1(LogTrace logTrace){ OrderRepositoryV1 orderRepository = new OrderRepositoryV1Impl(); // Proxy 객체 생성 OrderRepositoryV1 proxy = (OrderRepositoryV1) Proxy .newProxyInstance( OrderRepositoryV1.class.getClassLoader(), new Class[]{OrderRepositoryV1.class}, new LogTraceBasicHandler(orderRepository, logTrace)); return proxy; }} @Import(DynamicBasicProxyConfig.class)@SpringBootApplication(scanBasePackages = "hello.proxy.app") //주의public class ProxyApplication { public static void main(String[] args) { SpringApplication.run(ProxyApplication.class, args); } @Bean public LogTrace logTrace(){ return new ThreadLocalLogTrace(); }} 2021-11-28 22:18:58.331 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] OrderControllerV1.request()2021-11-28 22:18:58.333 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] |-->OrderServiceV1.orderItem()2021-11-28 22:18:58.333 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] | |-->OrderRepositoryV1.save()2021-11-28 22:18:59.338 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] | |<--OrderRepositoryV1.save() time=1005ms2021-11-28 22:18:59.338 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] |<--OrderServiceV1.orderItem() time=1006ms2021-11-28 22:18:59.339 INFO 3357 --- [nio-8080-exec-1] h.p.trace.logtrace.ThreadLocalLogTrace : [4e72efcd] OrderControllerV1.request() time=1007ms 특정 메소드에만 부가기능 로직 적용PatternMatchUtils.simpleMatch 를 사용해 메소드 이름이 조건을 만족하는지 Pattern Matching 한다.