AOP:Aspect-Oriented-Programming Overview
Last Updated on: February 8, 2021 pm
AOP Overview
AOP, at its core, lets you implement individual concerns in a loosely coupled fashion, and combine these implementations to form the final system. Indeed, AOP creates systems using loosely coupled, modularized implementations of crosscutting concerns. OOP, in contrast, creates systems using loosely coupled, modularized implementations of common concerns.
AOP Development Steps
Aspectual Decomposition
Identify Cross-cutting Concerns from common concerns.
There are two kinds of concerns: module-level concerns and crosscutting system-level concerns.
For example, in a credit card payment system, there should be three modules:
- Core Credit Card Payment Process - Module level
- Logging Module - Crosscutting
- Authentication - Crosscutting
Concern Implementation
In this step, you should implement each concern seperately.
Aspectual Recomposition
You need an aspect integrator to specify recomposition rules by creating aspects. The recomposition is known as weaving or integrating. This infomation is used to integrate the modules of the final system.
Terms in AOP
Cross-Cutting Concerns
Concerns = Functionality = Logic
Example: Loggin Concern. It always crosscuts every module in the system level. In other words, it should be applied to every module that needs loggin function.
Meanwhile, the normal concern’s implementation remains unware that other crosscutting concerns logging is “aspecting” it. For exanmple, the credit card processing module doesn’t know that other concerns are logging or authenticating its operations. The crosscutting concerns are like a proxy or some good spies that are monitoring on the operations and maintaining security of the entire system.
Proxy Design Pattern
通过代理,控制对对象的访问。
定义一个抽象角色,让代理角色和真实角色分别去实现它。
- 真实角色 -
implements AbstractRole
定义真正的业务逻辑,供代理角色使用。 - 代理角色 -
implements AbstractRole
通过真实角色的业务逻辑来实现抽象方法,并在抽象方法前后附加自己的代理操作。
Spring AOP 采用JDK动态代理和CGLIB动态代理。
如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP;如果目标对象没有实现了接口,则采用 CGLIB 库,Spring 会自动在 JDK 动态代理和 CGLIB 动态代理之间转换。
Weaving
The weaver assembles an individual concerns in the process of weaving.
In other words, the weaver interlaces different fragments based on some rules - weaving rules - applied to it.
Compile-time
AspectJ is based on Bytecode Manipulation.
Load-time
AspectJ
Run-time
Slowest.
Spring AOP - minor performance cost for aspect execution because of run-time weaving. It is based on Proxying.
Aspects
Module of code for cross-cutting concerns. (Eg. logging, transaction, security, …)
Advice
What action is taken and when it should be applied.
Advice defines pieces of an aspect implementation to be executed at pointcuts
Before
run before the method
After finally
run after the method - just like the Finally in try-catch block.
After returning
run after the method’s successful execution
After throwing
run after the method throws an exception.
Around
run before and after the method.
Join Points
Join points define specific points in a program’s execution.
It refers when to apply the code during the whole execution.
Point Cuts
A pointcut is the language construct that specifies join points.
A predicate expression for where the advice should be applied.
Benefits of AOP
AOP helps overcome the aforementioned problems caused by code tangling and code scattering.
- Modularized implementation of crosscutting concerns. - Code of Aspects is defined in a single class. AOP minimizes coupling and addresses cross-cutting concerns seperately. In general, it represents a higher reused of the Aspect code.
- Easier-to-evolve systems - Easier to add new aspect because the aspected modules are unaware of crosscutting concerns. And when you add a new functionality, the existinig aspects will also crosscut it.
Advice Type
@Before Advice Type
Create a Target Object: AccountDAO.java
1
2
3
4
5
6@Component
public class AccountDAO {
public void addAccount(){
System.out.println(getClass() + " : DOING MY DB WORK : ADDING ACCOUNT");
}
}Create a spring Java Config class - Pure Java Code
1
2
3
4
5@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.luv2code.aopdemo")
public class DemoConfig {
}Create main APP
1
2
3
4
5
6
7
8
9
10
11
12
13public class MainDemoApp {
public static void main(String[] args) {
// read spring config java class
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(DemoConfig.class);
// get the bean from the bean factory
AccountDAO theAccountDAO = context.getBean("accountDAO", AccountDAO.class);
// call the business method in the component
theAccountDAO.addAccount();
// close the spring context
context.close();
}
}Create an Aspect with
@Before
1
2
3
4
5
6
7
8
9
10@Aspect
@Component
public class MyDemoLoggingAspect {
// this is where we add all the related advices for logging
// @Before advice
@Before("execution(public void addAccount())")
public void beforeAddAccountAdvice(){
System.out.println("\n =====>>> Executing @Before advice on addAccount() method!");
}
}@AfterReturning Advice Type
Successful Execution(No Exception).
Add new method in AccountDAO
Add new Method called findAccounts()
in AccountDAO
.
Update Main app
1 |
|
Add @AfterReturning Advice
1 |
|
Use Case - Post-processing Data
- Post-processing the data before returning to the caller
- Format the data or enrich the data.
**Be careful when you modify the data! **
Convert every first name to Upper Case
1 |
|
@AfterThrowing Advice Type
Use Case
- Log the exception
- Perform auditing on the exception
- Notify DevOps team via email or SMS
- Encapsulate this functionality in AOP aspect for easy reuse
Modify Main App
1 |
|
Add @AfterThrowing Advice
1 |
|
Note: Make sure the parameter name theExc
and the throwing value name are matched.
@After Advice Type
@After will run for success or failure(finally).
Sequence Diagram
@After will execute before @AfterThrowing.
1 |
|
@Around Advice Type
Use Cases
Pre-processing and post-processing data
Instrumentation / profiling code
How long does it take for a section of code to run?
Managing Exception - Swallow / Handle / Stop Exceptions
Proceeding Join Point
Example:
Find out how long does it take to run the getFortune()
method?
1 |
|
Resolve Order Issue
Replace System.out.println
with logger.info()
private static Logger myLogger = Logger.getLogger(AroundDemoApp.class.getName());
Handling Exception
For an exception thrown from proceeding join point,
- You can handle / swallow / stop the exception
- Or you can simply rethrow the exception.
Handle / Swallow / Stop the Exception
@Around
advice calls the target method -getFortuneService
- There is an exception, go back to the
@Around
advice. @Around
advice handles the exception and sends back a regularresult
steam to the calling program.- The
result
stream makes it back to the AOP proxy and to main application. - The Main App never knows that exception is thrown because it is handle in the
@Around
advice.
Note: Do not hide the exceptions all the time. Use with caution. If it is a serious problem, just throw an exception to let everyone know.
1 |
|
Rethrow the Exception
1 |
|
PointCut
PointCut Expression
PointCut: a predicate expression for where advice should be applied.
Match Method and Return Types
1 |
|
- Patterns with “?” is optional.
- Patterns can use wildcards -
*
- matches everything
Match any addAccount() method that returns void in AccountDAO:
Match any addAccount() method in any class
@Before("execution(public void addAccount())")
Match methods starting with add returning void in any class
@Before("execution(public void add*())")
Match methods starting with add in any class
@Before("execution(* add*())")
Match Method Parameter Types
Match methods starting with add in any class with at least an Account para
@Before("execution(* add*(com.luv2code.aopdemo.Account, ..))")
Match all methods in a given class
PointCut Declarations
- Easily reuse pointcut expressions
- Update pointcut in one location
- Can also share and combine pointcut expressions
Create a pointcut declaration
1 |
|
Apply pointcut declaration to advices
1 |
|
Combine Pointcut Declarations
1 |
|
Apply to all method except “getter/setter”
1 |
|
Ordering Aspects
Refactor the advices into seperate Aspects and add @Order()
annotation.
1 |
|
Note: smaller number represents higher level of execution. -40 > -10 > 100
Read Method Arguments with JoinPoints
1. Access and display Method Signature
1 |
|
2. Access and display Method Arguments
1 |
|
Reference: [1]Udemy, Spring & Hibernate for Beginners (including SpringBoot) [2][I want my AOP](https://www.infoworld.com/article/2073918/i-want-my-aop---part-1.html) [3][SpringAOP & Proxy Pattern](https://blog.csdn.net/eson_15/article/details/84933442?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.not_use_machine_learn_pai)