Spring AOP (Aspect Oriented Programming)
Spring AOP 에서 Proxy 모드를 사용하는데는 두가지 방법이 있다.
- JDK Dynamix proxy
- 인터페에스가 존재해야 한다.
- 인터페이스를 기준으로 proxy 를 생성한다
- 리플리케이션을 통해 동적으로 프록시 객체를 생성한다.
- CGLib Proxy : 구현체만 있어도 된다.
<aop:config proxy-target-class=”true” >
설정을 해주어야 한다. 어노테이션으로는 다음과 같다.@EnableAspectJAutoProxy(proxyTargetClass = true)
- Springboot 에서는 CGLib 라이브러리가 안정화 되었다고 보고 라이브러리가 포함되어 있다.
- class 상속을 통해 proxy 객체를 생성한다.
- inferface, class 기준으로 proxy 를 생성한다.
- 타겟 클레스의 바이트코드를 조적하여 재정의 함으로 final 사용은 불가하다.
Spring paroxyTargetClass 의 의미 ?
스프링에서는 프록시를 구현할때 기존방식처럼 인터페이스를 이용한 JDK Dynamic 을 이용할것인지 또는 해당 클레스 바이트를 직접 조작하여 CGLib proxy 를 사용 할것인지에 대한 옵션을 제공하고 있는데 이것이 proxyTargetClass 이다. true 로 사용하연 클래스를 직접 조작하겠다는 의미로 CGLib Proxy 를 사용한다.
Spring AOP Advice 생명주기
- Befor
- target 메소드 호출전에 적용
- After returning
- 타겟 메소드 호출후에 적용
- After Throwing
- 타겟에서 예외 발생후 적용
- After
- 타겟 메호드 호출후 예외 발생 상관 없이 적용
- Around
- 타겟 메소드 호출 전/후 에 적용됨
2022-03-25 17:04:30.090 TRACE 40768 --- [ Test worker] o.s.aop.framework.JdkDynamicAopProxy : Creating JDK dynamic proxy: SingletonTargetSource for target object [skan.aop.MemberServiceImpl@64aad809]
1. JDK Dynamic Proxy 방식 AOP 예제
JDK Dynamic Proxy 방식 으로 개발을 하기 원할때는 몇 가지 설정을 변경해 주어야 한다.
프로퍼티를 spring.aop.proxy-target-class=false
기본으 true 이기때문에 false로 변경 한다. 이렇게 하면 인터페이스에 AOP 의 advice 걸어서 사용 할 수 있다.
application.properties
프로퍼티에서 proxy target class 를 false 로 변경하여 jdk dynamic proxy를 사용하도록 한다.
spring.aop.proxy-target-class=false
logging.level.root=INFO
logging.level.org.springframework.aop=trace
@Retry
인터페이스에 적용할 Advice 용 @annotation 을 생성한다.
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {
/**
* retry 횟수
*/
int value() default 3;
}
AspectMemberService.java
AOP가 동잘될 지점과 내용을 설정한다.
@Slf4j
@Aspect
@Component
public class AspectMemberService {
@Before("@annotation(skan.annotation.Retry)")
public void doSomethingBefore(JoinPoint joinPoint) {
log.info("------------------------ BEFORE START ");
log.info("before joinPoint= {}", joinPoint.getKind());
Arrays.stream(joinPoint.getArgs()).
map(o -> "+plus")
.collect(Collectors.toList());
;
log.info("------------------------ BEFORE END ");
}
@Around(value ="execution(* skan.aop.MemberService.save(String))" +"@annotation(skan.annotation.Retry)")
public Object processed(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
log.info("------------------------ AOP-PLAIN : START ");
long begin = System.currentTimeMillis();
log.info("args = {}",proceedingJoinPoint.getArgs());
log.info("signature = {}",proceedingJoinPoint.getSignature());
log.info("target = {}",proceedingJoinPoint.getTarget());
log.info("static part = {}",proceedingJoinPoint.getStaticPart());
log.info("kind = {}",proceedingJoinPoint.getKind());
log.info("source location = {}",proceedingJoinPoint.getSourceLocation());
log.info("this = {}",proceedingJoinPoint.getThis());
log.info("class = {}",proceedingJoinPoint.getClass());
Object retVal = proceedingJoinPoint.proceed(); // 메서드 호출 자체를 감쌈
log.info("aspect 실행 시간 = {} ", System.currentTimeMillis() - begin);
log.info("------------------------ AOP-PLAIN : END ");
log.info("------------------------ AOP-ANNOTATION VALUE : START");
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Retry retry = methodSignature.getMethod().getAnnotation(Retry.class);
log.info("retry count = {} ", retry.value());
log.info("------------------------ AOP-ANNOTATION VALUE : END");
return retVal;
}
@AfterReturning(value = "@annotation(skan.annotation.Retry)", returning = "returnObject")
public void doSomethingAfter(JoinPoint joinPoint, Object returnObject) {
log.info("------------------------ AFTER : START ");
log.info("after returning joinPoint = {}", joinPoint.getKind());
log.info("after returning object = {}", returnObject);
log.info("------------------------ AFTER : END");
}
@AfterThrowing(value = "@annotation(skan.annotation.Retry)", throwing = "exception")
public void afterThrowing(JoinPoint joinPoint , Exception exception) {
log.error("aop throwing",exception);
}
}
**MemberService
.java**
인터페이스 설정 @Retry 적용
public interface MemberService {
@Retry
String save(String test_data);
@Retry(1)
int delete(String data) throws Exception;
}
MemberServiceImpl.java
인터페이스를 상속 받은 구현체 비지니스 로직 구현.
@Service
@Slf4j
public class MemberServiceImpl implements MemberService {
public String save(String data) {
log.info("data = {}", data);
return "DATA SAVE SUCCESS";
}
public int delete(String data) throws Exception{
Random random = new Random();
// try catch block 에 의해 aspectThrowing 은 동작하지 안는다.
// try-catch block 을 삭제 하면 다시 aspect 에 검사된다.
//try {
if (random.nextBoolean()) {
throw new RuntimeException("delete 예외발생");
}
log.info("delete 성공 !!! ");
//} catch (Exception e) {
// e.printStackTrace();
//}
return 0;
}
}
SrpingApplication.java
@Slf4j
@SpringBootApplication
public class SrpingApplication {
public static void main(String[] args) {
SpringApplication.run(SrpingApplication.class);
}
}
MemberServiceImplTest.java
테스트 케이스 생성
@SpringBootTest
class MemberServiceImplTest {
@Autowired MemberService memberService;
@Test
@DisplayName("저장 AOP")
public void save() throws Exception {
memberService.save("memeber name");
}
@Test
@DisplayName("예외를 일으켜 AOP 확인하기 ")
public void aopException() throws Exception {
memberService.delete("");
}
}
Dynamic proxy log 확인
정확한 확인을 위해 org.springframework.aop 의 로그 레벨을 trace로 한다.
Creating JDK dynamic
로그에서 해당 문구를 확인 할 수 있다
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.7)
2022-03-25 19:08:31.722 INFO 41947 --- [ Test worker] skan.aop.MemberServiceImplTest : Starting MemberServiceImplTest using Java 11.0.11 on mezzoui-MacBookPro.local with PID 41947 (started by mezzo-skan in /Users/mezzo-skan/git/progream.study/spring.skan.study/springboot.aop/springboot.default.001)
2022-03-25 19:08:31.723 INFO 41947 --- [ Test worker] skan.aop.MemberServiceImplTest : No active profile set, falling back to default profiles: default
2022-03-25 19:08:32.028 DEBUG 41947 --- [ Test worker] .s.a.a.a.ReflectiveAspectJAdvisorFactory : Found AspectJ method: public java.lang.Object skan.aop.AspectMemberService.processed(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
2022-03-25 19:08:32.029 DEBUG 41947 --- [ Test worker] .s.a.a.a.ReflectiveAspectJAdvisorFactory : Found AspectJ method: public void skan.aop.AspectMemberService.doSomethingBefore(org.aspectj.lang.JoinPoint)
2022-03-25 19:08:32.029 DEBUG 41947 --- [ Test worker] .s.a.a.a.ReflectiveAspectJAdvisorFactory : Found AspectJ method: public void skan.aop.AspectMemberService.doSomethingAfter(org.aspectj.lang.JoinPoint,java.lang.Object)
2022-03-25 19:08:32.036 DEBUG 41947 --- [ Test worker] .s.a.a.a.ReflectiveAspectJAdvisorFactory : Found AspectJ method: public void skan.aop.AspectMemberService.afterThrowing(org.aspectj.lang.JoinPoint,java.lang.Exception)
2022-03-25 19:08:32.156 TRACE 41947 --- [ Test worker] a.AnnotationAwareAspectJAutoProxyCreator : Creating implicit proxy for bean 'memberServiceImpl' with 0 common interceptors and 2 specific interceptors
2022-03-25 19:08:32.158 TRACE 41947 --- [ Test worker] o.s.aop.framework.JdkDynamicAopProxy : Creating JDK dynamic proxy: SingletonTargetSource for target object [skan.aop.MemberServiceImpl@57cb70be]
2022-03-25 19:08:32.252 INFO 41947 --- [ Test worker] skan.aop.MemberServiceImplTest : Started MemberServiceImplTest in 0.739 seconds (JVM running for 1.577)
2022-03-25 19:08:32.254 INFO 41947 --- [ Test worker] skan.SrpingApplication : init str = {}
2022-03-25 19:08:32.531 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : ------------------------ AOP-PLAIN : START
2022-03-25 19:08:32.531 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : args = memeber name
2022-03-25 19:08:32.532 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : signature = String skan.aop.MemberService.save(String)
2022-03-25 19:08:32.532 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : target = skan.aop.MemberServiceImpl@57cb70be
2022-03-25 19:08:32.532 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : static part = execution(String skan.aop.MemberService.save(String))
2022-03-25 19:08:32.532 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : kind = method-execution
2022-03-25 19:08:32.533 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : source location = org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@28279a49
2022-03-25 19:08:32.533 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : this = skan.aop.MemberServiceImpl@57cb70be
2022-03-25 19:08:32.533 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : class = class org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint
2022-03-25 19:08:32.533 INFO 41947 --- [ Test worker] skan.aop.MemberServiceImpl : data = memeber name
2022-03-25 19:08:32.534 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : aspect 실행 시간 = 3
2022-03-25 19:08:32.534 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : ------------------------ AOP-PLAIN : END
2022-03-25 19:08:32.534 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : ------------------------ AOP-ANNOTATION VALUE : START
2022-03-25 19:08:32.534 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : retry count = 3
2022-03-25 19:08:32.537 INFO 41947 --- [ Test worker] skan.aop.AspectMemberService : ------------------------ AOP-ANNOTATION VALUE : END
BUILD SUCCESSFUL in 2s
4 actionable tasks: 4 executed
7:08:32 오후: Task execution finished ':springboot.aop:springboot.default.001:test --tests "skan.aop.MemberServiceImplTest.save"'.
2. CGLib proxy AOP 예제
jdk 다이나믹 프록시와 다르게 인터페이스를 구현하지 않고 오로지 클레스로만 사용한다. 클레스자체가 프록시로 생성됨으로 final 을 사용하면 사용이 불가능 하다.
SpringBoot 에서는 proxyTargetClass
가 기본 true 임으로 프로퍼티를 수정하지 않고 실행한다. @SpringBootApplication 안에 내부를 살펴보면 @EnableAspectJAutoProxy
도 선언되어 있다.
앞서도 이야기 했지만 CGLib proxy 의 가장큰 차이점은 인터페이스를 생성하지 않고 Class 에서 바이트코드를 만들어 proxy 한다느것이다. 즉 inferface를 만들지 않고 Class 만생성하여 advice 를 할 수 있다.
인터페이스가 없음으로 좀더 간결하게 작성가능하다.
**Retry
.class**
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {
/**
* retry 횟수
*/
int value() default 3;
}
**AspectMemberService
.class**
@Slf4j
@Aspect
@Component
public class AspectMemberService {
@Before("@annotation(skan.annotation.Retry)")
public void doSomethingBefore(JoinPoint joinPoint) {
log.info("------------------------ BEFORE START ");
log.info("before joinPoint= {}", joinPoint.getKind());
Arrays.stream(joinPoint.getArgs()).
map(o -> "+plus")
.collect(Collectors.toList());
;
log.info("------------------------ BEFORE END ");
}
@Around(value ="execution(* skan.aop.MemberService.save(String))" +"@annotation(skan.annotation.Retry)")
public Object processed(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
log.info("------------------------ AOP-PLAIN : START ");
long begin = System.currentTimeMillis();
log.info("args = {}",proceedingJoinPoint.getArgs());
log.info("signature = {}",proceedingJoinPoint.getSignature());
log.info("target = {}",proceedingJoinPoint.getTarget());
log.info("static part = {}",proceedingJoinPoint.getStaticPart());
log.info("kind = {}",proceedingJoinPoint.getKind());
log.info("source location = {}",proceedingJoinPoint.getSourceLocation());
log.info("this = {}",proceedingJoinPoint.getThis());
log.info("class = {}",proceedingJoinPoint.getClass());
Object retVal = proceedingJoinPoint.proceed(); // 메서드 호출 자체를 감쌈
log.info("aspect 실행 시간 = {} ", System.currentTimeMillis() - begin);
log.info("------------------------ AOP-PLAIN : END ");
log.info("------------------------ AOP-ANNOTATION VALUE : START");
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Retry retry = methodSignature.getMethod().getAnnotation(Retry.class);
log.info("retry count = {} ", retry.value());
log.info("------------------------ AOP-ANNOTATION VALUE : END");
return retVal;
}
@AfterReturning(value = "@annotation(skan.annotation.Retry)", returning = "returnObject")
public void doSomethingAfter(JoinPoint joinPoint, Object returnObject) {
log.info("------------------------ AFTER : START ");
log.info("after returning joinPoint = {}", joinPoint.getKind());
log.info("after returning object = {}", returnObject);
log.info("------------------------ AFTER : END");
}
@AfterThrowing(value = "@annotation(skan.annotation.Retry)", throwing = "exception")
public void afterThrowing(JoinPoint joinPoint , Exception exception) {
log.error("aop throwing",exception);
}
}
MemberService.java
@Service
@Slf4j
public class MemberService {
@Retry(2)
public String save(String data) {
log.info("data = {}", data);
return "DATA SAVE SUCCESS";
}
@Retry(3)
public int delete(String data) throws Exception{
Random random = new Random();
// try catch block 에 의해 aspectThrowing 은 동작하지 안는다.
// try-catch block 을 삭제 하면 다시 aspect 에 검사된다.
//try {
if (random.nextBoolean()) {
throw new RuntimeException("delete 예외발생");
}
log.info("delete 성공 !!! ");
//} catch (Exception e) {
// e.printStackTrace();
//}
return 0;
}
}
SrpingApplication
.java
@Slf4j
@SpringBootApplication
public class SrpingApplication {
public static void main(String[] args) {
SpringApplication.run(SrpingApplication.class);
}
}
CGlib proxy log 확인
o.s.aop.framework.CglibAopProxy
의 로그로 cglib proxy 로 활성화 된것을 확인 할 수있다.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.7)
2022-03-28 10:01:26.270 INFO 1524 --- [ Test worker] skan.aop.MemberServiceImplTest : Starting MemberServiceImplTest using Java 11.0.11 on mezzoui-MacBookPro.local with PID 1524 (started by mezzo-skan in /Users/mezzo-skan/git/progream.study/spring.skan.study/springboot.aop/springboot.cglib.aop)
2022-03-28 10:01:26.271 INFO 1524 --- [ Test worker] skan.aop.MemberServiceImplTest : No active profile set, falling back to default profiles: default
2022-03-28 10:01:26.612 DEBUG 1524 --- [ Test worker] .s.a.a.a.ReflectiveAspectJAdvisorFactory : Found AspectJ method: public java.lang.Object skan.aop.AspectMemberService.processed(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
2022-03-28 10:01:26.614 DEBUG 1524 --- [ Test worker] .s.a.a.a.ReflectiveAspectJAdvisorFactory : Found AspectJ method: public void skan.aop.AspectMemberService.doSomethingBefore(org.aspectj.lang.JoinPoint)
2022-03-28 10:01:26.615 DEBUG 1524 --- [ Test worker] .s.a.a.a.ReflectiveAspectJAdvisorFactory : Found AspectJ method: public void skan.aop.AspectMemberService.doSomethingAfter(org.aspectj.lang.JoinPoint,java.lang.Object)
2022-03-28 10:01:26.622 DEBUG 1524 --- [ Test worker] .s.a.a.a.ReflectiveAspectJAdvisorFactory : Found AspectJ method: public void skan.aop.AspectMemberService.afterThrowing(org.aspectj.lang.JoinPoint,java.lang.Exception)
2022-03-28 10:01:26.750 TRACE 1524 --- [ Test worker] a.AnnotationAwareAspectJAutoProxyCreator : Creating implicit proxy for bean 'memberServiceImpl' with 0 common interceptors and 5 specific interceptors
2022-03-28 10:01:26.752 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Creating CGLIB proxy: SingletonTargetSource for target object [skan.aop.MemberServiceImpl@43f9dd56]
2022-03-28 10:01:26.757 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Unable to apply any optimizations to advised method: public int skan.aop.MemberServiceImpl.delete(java.lang.String) throws java.lang.Exception
2022-03-28 10:01:26.757 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Unable to apply any optimizations to advised method: public java.lang.String skan.aop.MemberServiceImpl.save(java.lang.String)
2022-03-28 10:01:26.758 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Found 'equals' method: public boolean java.lang.Object.equals(java.lang.Object)
2022-03-28 10:01:26.758 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Unable to apply any optimizations to advised method: public java.lang.String java.lang.Object.toString()
2022-03-28 10:01:26.759 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Found 'hashCode' method: public native int java.lang.Object.hashCode()
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Unable to apply any optimizations to advised method: protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isProxyTargetClass()
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setTargetSource(org.springframework.aop.TargetSource)
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setExposeProxy(boolean)
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isExposeProxy()
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.setPreFiltered(boolean)
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isPreFiltered()
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.removeAdvisor(int) throws org.springframework.aop.framework.AopConfigException
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvisor(org.springframework.aop.Advisor)
2022-03-28 10:01:26.760 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.replaceAdvisor(org.springframework.aop.Advisor,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.removeAdvice(org.aopalliance.aop.Advice)
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract java.lang.String org.springframework.aop.framework.Advised.toProxyConfigString()
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isInterfaceProxied(java.lang.Class)
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public default int org.springframework.aop.framework.Advised.getAdvisorCount()
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract java.lang.Class[] org.springframework.aop.framework.Advised.getProxiedInterfaces()
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract org.springframework.aop.Advisor[] org.springframework.aop.framework.Advised.getAdvisors()
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract org.springframework.aop.TargetSource org.springframework.aop.framework.Advised.getTargetSource()
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2022-03-28 10:01:26.761 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvisor(int,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException
2022-03-28 10:01:26.762 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(int,org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2022-03-28 10:01:26.762 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException
2022-03-28 10:01:26.762 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.aopalliance.aop.Advice)
2022-03-28 10:01:26.762 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract int org.springframework.aop.framework.Advised.indexOf(org.springframework.aop.Advisor)
2022-03-28 10:01:26.762 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract boolean org.springframework.aop.framework.Advised.isFrozen()
2022-03-28 10:01:26.762 TRACE 1524 --- [ Test worker] o.s.aop.framework.CglibAopProxy : Method is declared on Advised interface: public abstract java.lang.Class org.springframework.aop.TargetClassAware.getTargetClass()
2022-03-28 10:01:26.883 INFO 1524 --- [ Test worker] skan.aop.MemberServiceImplTest : Started MemberServiceImplTest in 0.833 seconds (JVM running for 1.798)
2022-03-28 10:01:26.884 INFO 1524 --- [ Test worker] skan.SrpingApplication : init str = {}
2022-03-28 10:01:27.193 INFO 1524 --- [ Test worker] skan.aop.AspectMemberService : ------------------------ AOP-PLAIN : START