Framework/SPRING

Spring AOP

데먕 2019. 8. 23. 06:32

1. Overview

AOP is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code without modification of the code itself.

1.1 Code Tangling, Scattering, and Cross-Cutting Concerns

 

Problems Without AOP or Modularization are Code Tangling and Code Scattering.

1.1.1 cross-cutting concern

A cross-cutting concern is a concern that can affect the whole application and should be centralized in one location in code as possible, such as transaction management, authentication, logging, security, and so on.

1.1.2 Code Tangling

Code tangling means mixing crosscutting concerns and business logic, which in turn leads to tight coupling. Let's look at the following diagram to understand code tangling:

The preceding diagram illustrates how we mix transactions and security code along with our business logic in our service implementation. With such implementation, code reusability is reduced, maintenance is degraded, and the single responsibility principle is violated.

1.1.3 Code Scattering

Concerns are dispersed over many modules

1.2 Usage

  • Logging and Tracing
  • Transaction Management
  • Security
  • Caching
  • Error Handling
  • Performance Monitoring

2. Description

Below are the core concepts of Spring AOP implementation.

2.1 Aspect

An aspect is a class that implements enterprise application concerns that cut across multiple classes, such as transaction management. And also it's a combination of the pointcut and the advice. Aspects can be a normal class configured through Spring XML configuration or Using Spring AspectJ integration to define a class as Aspect using @Asepct annotation. Aspect can be reused at multiple locations.

2.2 Advice

Advice is actions taken for a particular join point. 

2.2.1 Before Advice

it executes before a join point

2.2.2 After Returning Advice

it executes after a join point completes normally.

2.2.3 After Throwing Advice

it executes if a method exits by throwing an exception.

2.2.4 After (finally) Advice

it executes after a join point regardless of join point exit whether normally or exceptional return. 

2.2.5 Around Advice

It executes before and after a join point

2.3 Pointcut

This is predicate helps match an Advice to be applied by an Aspect at a particular JoinPoint. The Advice is often associated with a Pointcut expression and runs at any JoinPoint matched by the Pointcut.

Pointcut JoinPoints
execution(public * * (..)) public method
execution(* set*(..)) all methods named prefix 'set'
execution(* get*(..)) all methods named prefix 'get'
execution(* com.xyz.service.AccountService.*(..)) all methods of AccountService interface
execution(* com.xyz.service.*.*(..)) all mehods of service package
execution(* com.xyz.service..*.*(..)) all methods of service package and nested package
within(com.xyz.service.*) all join point of service package(include classes)
within(com.xyz.service..*) all join point of service package and nested package(include classes)
bean(*Repository) all beans of postfix 'Repository'
bean(*) all beans
bean(account*) all beans of prefix 'account'
bean(*dataSource) || bean(*DataSource) all beans of postfix 'dataSource' or 'DataSource'

2.3.1 Pointcut Designators

  • execution
  • within
  • this
  • target
  • args
  • @target
  • @args
  • @within
  • @annotation

2.3.2 Pointcut Expression Language

execution(modifier-pattern? return-type-pattern declaring-type-pattern? 
		  method-name-pattern(param-pattern) throws-patterns?)

2.4 Target Object

They are the object being advised by one or more aspects. It is also known as a proxied object in spring because Spring AOP is implemented using runtime proxies. 

2.5 JoinPoint

A join point is a specific point in the application such as method execution, exception handling, changing object variable values, etc. In Spring AOP a join point is always the execution of a method.

2.6 AOP proxy

Spring AOP implementation uses JDK dynamic proxy or CGLIB to create the Proxy classes with target classes and advice invocations, these are called AOP proxy classes.

2.7 Weaving

It is the process of linking aspects with other objects to create advised proxy objects. It is also known as a proxied object in spring object in spring because Spring AOP is implemented using runtime proxies.

3. Example

This is a sample code of the annotation approach and using spring-boot-starter-aop.

@Component
@Aspect
public class PerfAspect {

@Around("execution(* com.saelobi..*.EventService.*(..))")
    public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
    long begin = System.currentTimeMillis();
    Object retVal = pjp.proceed(); // wrapping method invoking
    System.out.println(System.currentTimeMillis() - begin);
    return retVal;
  }
}

@Aspect annotation denotes this class is an Aspect class and also using @component assign it to spring bean pool. and @Around means wrapping target methods which match pointcut expression which is using execution pointcut designator(PCD).

public interface EventService {

    void createEvent();

    void publishEvent();

    void deleteEvent();
}
@Component
public class SimpleEventService implements EventService {

    @Override
    public void createEvent() {
        try {
            Thread.sleep(1000);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Created an event");
    }

    @Override
    public void publishEvent() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e){
            e.printStackTrace();;
        }
        System.out.println("Published an event");
    }

    public void deleteEvent() {
        System.out.println("Delete an event");
    }
}
@Service
public class AppRunner implements ApplicationRunner {

    @Autowired
    EventService eventService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        eventService.createEvent();
        eventService.publishEvent();
        eventService.deleteEvent();
    }
}
Created an event
1003
Published an event
1000
Delete an event
0

 

Also using @annotation PCD, you can weave specific join point as below. Only methods attached @PerLogging annotation are weaved with PerfAspect.

@Component
@Aspect
public class PerfAspect {

@Around("@annotation(PerLogging)")
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
    long begin = System.currentTimeMillis();
    Object retVal = pjp.proceed(); 
    System.out.println(System.currentTimeMillis() - begin);
    return retVal;
  }
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface PerLogging {
}
@Component
public class SimpleEventService implements EventService {

    @PerLogging
    @Override
    public void createEvent() {
        try {
            Thread.sleep(1000);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Created an event");
    }

    @Override
    public void publishEvent() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e){
            e.printStackTrace();;
        }
        System.out.println("Published an event");
    }

    @PerLogging
    @Override
    public void deleteEvent() {
        System.out.println("Delete an event");
    }
}
Created an event
1003
Published an event
Delete an event
0

 

Also, all of the specific beans can be weaved using bean PCD as below. You can see only SimpleEventService's methods are weaved.

@Component
@Aspect
public class PerfAspect {

@Around("bean(simpleEventService)")
  public Object logPerf(ProceedingJoinPoint pjp) throws Throwable{
    long begin = System.currentTimeMillis();
    Object retVal = pjp.proceed(); // 메서드 호출 자체를 감쌈
    System.out.println(System.currentTimeMillis() - begin);
    return retVal;
  }
}
@Component
public class SimpleEventService implements EventService {

    @Override
    public void createEvent() {
        try {
            Thread.sleep(1000);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Created an event");
    }

    @Override
    public void publishEvent() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e){
            e.printStackTrace();;
        }
        System.out.println("Published an event");
    }
    
    @Override
    public void deleteEvent() {
        System.out.println("Delete an event");
    }
}
@Service
public class AppRunner implements ApplicationRunner {

    @Autowired
    EventService eventService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        eventService.createEvent();
        eventService.publishEvent();
        eventService.deleteEvent();
    }
}
Created an event
1002
Published an event
1001
Delete an event
0

 

4. References

https://howtodoinjava.com/spring-aop-tutorial/

https://mossgreen.github.io/Spring-Certification-Spring-AOP/

https://www.baeldung.com/spring-aop-vs-aspectj

https://www.dineshonjava.com/spring-aop-tutorial-with-example-aspect-advice-pointcut-joinpoint/

https://www.baeldung.com/spring-aop-pointcut-tutorial

https://www.slideshare.net/taemonz/spring-framework-aop-23721816

https://engkimbs.tistory.com/746

https://www.baeldung.com/spring-aop-pointcut-tutorial

https://www.researchgate.net/figure/Code-scattering-and-code-tangling_fig2_327338379

https://www.oreilly.com/library/view/hands-on-high-performance/9781788838382/21d99753-67b4-40e3-b662-7d6f3267458e.xhtml

https://howtodoinjava.com/spring-aop-tutorial/

https://m.blog.naver.com/PostView.nhn?blogId=tlsdlf5&logNo=220691336157&proxyReferer=https%3A%2F%2Fwww.google.com%2F