⇒ 공통 모듈을 프록시로 만들어서 DI 로 연결된 빈 사이에 적용해 Target의 메소드 호출 과정에 참여애 부가기능(공통 모듈)을 제공해준다.
그렇기의 JDK 와 Spring Container 외에 특별한 기술 및환경을 요구하지 않는다.
Advice 가 구현하는 MethodInterceptor 인터페이스는 다이내믹 프록시의 InvocationHandler와 마찬가지로 프록시부터 메소드 요청정보를 전달받아 타깃 오브젝트의 메소드를 호출하는데, 이렇게 메소드를 호출하는 전/후로 부가기능(공통 모듈)을 제공할 수 있다.
이런식으로 독립적으로 개발한 부가기능 모듈을 다양한 타깃 오브젝트의 메소드에 다이내믹하게 적용해주기 위해 가장 중요한 역할을 맡고 있는게 프록시고, 스프링 AOP는 프록시 방식의 AOP라 할 수 있다.
AOP를 이용해 시간측정 Bean(ExampleService) 개선 - Execution expression
공통 모듈분석
⇒ 위 코드(ExampleServiceImpl)을 보면 StopWatch 를 이용해 성능측정을 하는부분이 start, process , end 메서드에 모두 포함된다.
그렇기 때문에 해당 코드는 공통모듈로 묶어서 정의할 수 있다.
공통 모듈추출 및 구현
package io.security.corespringsecurity.aopsecurity;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
@Component
@Aspect
public class PerfAspect {
// io.security.corespringsecurity.aopsecurity.ExampleService 클래스내의 모든 메서드에 공통 모듈을 적용한다.
@Around(value = "execution(* io.security.corespringsecurity.aopsecurity.ExampleService.*(..))")
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object retVal = pjp.proceed();
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());
return retVal;
}
}
package io.security.corespringsecurity.aopsecurity;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
@Component
public class ExampleServiceImpl implements ExampleService {
@Override
public void start() {
try {
Thread.sleep(1000);
System.out.println("start");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void process() {
try {
Thread.sleep(1000);
System.out.println("processing");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void end() {
try {
Thread.sleep(1000);
System.out.println("ended");
} catch (Exception e) {
e.printStackTrace();
}
}
}
package io.security.corespringsecurity.aopsecurity;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ExampleServiceImplTest {
@Autowired
ExampleService service;
@Test
public void exampleTest() throws Exception {
service.start();
service.process();
service.end();
}
}
기존과 차이점이 있다면, @Aspect 를 적용하기위해 @SpringBootTest 어노테이션을 추가해서 해당 @Aspect를 등록해주고 ExampleService도 DI해줬다.
참고: Advice 정의(@Aspect)시 Point cut시점을 정의할 수 있는데 위 예제는 @Around로 정의되었지만
@Before나 @After와같은 어노테이션도 존재한다.
출처:https://catsbi.oopy.io/fb62f86a-44d2-48e7-bb9d-8b937577c86c