Spring

[Spring] 예제로 보는 Aspect Oriented Programming with Spring

KEMON 2020. 6. 7. 21:39
728x90

AOP : 관점지향프로그래밍 (aspect- oriented programming)

 

Spring AOP : schema-based approach  or @AspectJ 

 

1. AOP Concepts

Aspect : before , after , throws , finally 같은 것들을 관리해준다

               Transaction management  - 실제 비즈니스 로직에서는 트랜잭션 코드를 숨길 있다 

 

Join point : Aspect가 동작해야 될 포인트 

Advice : Join 포인트가 언제 동작할건지 관리 (before, after , around)

pointcut : 조인 포인트를 판단하는것 인데 어떻게 포인트 컷을 걸지 포인트컷 하나에 여러개의 조인 포인트가 생길 수 있다 

target object : 각각의 aop가 동작되어야 할 타겟

AOP proxy : jdk dynamic proxy or CGLIB proxy 사용

weaving : Aspect join point 동작되는 곳을 왔다 갔다 하는 것을 위빙 , Spring 에서는 runtime weaving 한다

 

Advice 종류 (5개의 Advice 제공)

  • before : 특정 조인 포인트 전에 동작하는 Advice
  • after(returning) : 조인 포인트가 동작하고나서 문제없을 시 동작하는 Advice
  • after(throwing) : 조인 포인트가 동작을 하다가 Exception을 발생시켰을 때 동작하는 Advice
  • after : 정상 혹은 에러일 때 둘 다 finally 처럼 동작하는 Advice
  • around : 보통 많이 쓰이는데 before, after 등 위의 4가지를 하나로 합쳐놓은 것과 같다.

2. AOP Proxies

JDK dynamic proxies : 인터페이스만 제공 그러므로 구현클래스의 경우 사용 불가

(인터페이스를 이용해서 사용)

CGLIB proxices : 클래스를 이용해서 사용 

public class Main {
    public static void main(String[] args) throws SQLException {
        Pojo pojo = new SimplePojo();
        pojo.foo();
        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new RetryAdvice());
        Pojo pojo = (Pojo) factory.geAtProxy();
        System.out.println(">>>");
        pojo.foo();
        System.out.println(">>>");
   

        context.close();

    }

}

class RetryAdvice implements MethodInterceptor{ //spring에서 제공하는 일종의 AOP
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
         //return null; // return null 하면 프록시 사이의 함수가 동작 안한다
        System.out.println("before"); //이런식으로 before , after 로직도 구현 가능
        Object proceed= methodInvocation.proceed();
        System.out.println("after");
        return proceed; //이렇게 리턴을 해야 프록시 사이의 함수가 작동
    }
}
interface Pojo{
    void foo();
}
class SimplePojo implements Pojo{
    public void foo(){
        System.out.println("run foo");
    }
}

Plain Object를 호출하기 전에 프로기로 감싼다

실제 프록시를 통해서 오브젝트를 호출

 

프록시에 감싸져있던 foo() 실행

 

3. @Aspectj support

1. Enabling @AspectJ Support

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

}

 

2. Declaring an Aspect

@Aspect
public class NotVeryUsefulAspect {

}

3. Declaring a Pointcut

@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature

4. Declaring Advice

    1) Before Advice

@Aspect
public class BeforeExample {

    @Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }

}

    2) After Returning Advice

@Aspect
public class AfterReturningExample {

    @AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }

}

    3) After Throwing Advice

@Aspect
public class AfterThrowingExample {

    @AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
    public void doRecoveryActions() {
        // ...
    }

}

    4) After (Finally) Advice

@Aspect
public class AfterFinallyExample {

    @After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
    public void doReleaseLock() {
        // ...
    }

}

    5) Around Advice

@Aspect
public class AroundExample {

    @Around("com.xyz.myapp.SystemArchitecture.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }

}

 

 

※AOP를 사용하면 실제로 비즈니스 코드를 분리할 수 있는 강점이 있다.

728x90