AOP là gì? Ví dụ về AOP sử dụng Spring Framework
NỘI DUNG BÀI VIẾT
1. AOP trong Spring Framwork là gì?
Aspect Oriented Programming (AOP) Spring Framwork là 1 kỹ thuật lập trình dùng để tách logic chương trình thành các phần riêng biệt…
Trong Spring AOP, có 4 loại advice được hỗ trợ:
- Before advice: chạy trước khi method được thực thi
- After returning advice: Chạy sau khi method trả về một kết quả
- After throwing adivce: Chạy khi method ném ra một exception
- Around advice: Chạy khi method được thực thi (Bao gồm cả 3 loại advice trên)
Khi hoạt động, chương trình sẽ kết hợp các module lại để thực hiện các chức năng nhưng khi sửa đổi 1 chức năng thì chỉ cần sửa 1 module.
AOP không phải dùng để thay thế OOP mà để bổ sung cho OOP.
2. Demo về AOP Spring Framework
Một số khái nhiệm và thuật ngữ trong AOP với Spring Framework:
- Join point: là các điểm trong chương trình ví dụ điểm thực thi method (method execution), điểm xử lý excpetion, field access… Spring chỉ hỗ trợ method execution join point
- Advice: một hành động thực hiện ở joint point
- Pointcut: Là expression language giúp khớp nối với joint point
- Introduction: Cho phép introduce các new interface tới bất kì object adviced nào.
- Target Object: Object sẽ được adviced
- Aspect: là một class bao gồm các advice và các joint point
- Interceptor: là một aspect chỉ có duy nhất một advice
- AOP Proxy: dùng để cài đặt các Aspect
- Weaving: là tiến trình nối các aspect với các object, types để tạo nên advised object.
2.1 Maven dependency
pom.xml:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
Code language: HTML, XML (xml)
HelloWorld.java:
Tổng hợp 200+ tài liệu, sách, bài thực hành, video hướng dẫn lập trình… từ cơ bản đến nâng cao
public class HelloWorld {
public void method1() {
System.out.println("-------------------------------------");
System.out.println("method 1");
}
public void method2() {
System.out.println("-------------------------------------");
System.out.println("method 2");
}
public void method3() {
System.out.println("-------------------------------------");
System.out.println("method 3");
throw new IllegalArgumentException();
}
}
Code language: PHP (php)
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.hdd.HelloWorld" />
</beans>
Code language: HTML, XML (xml)
Demo
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
helloWorld.method1();
helloWorld.method2();
}
Code language: JavaScript (javascript)
output:
-------------------------------------
method 1
-------------------------------------
method 2
2.2 Áp dụng before advice
Tạo class DemoBeforeAdvice.java định nghĩa hành động trước khi cách method của class HelloWorld được chạy:
- MethodBeforeAdvice: là một aspect đồng thời cũng là một Interceptor vì nó chỉ có 1 advice.
- DemoBeforeService: là một AOP proxy, nó cài đặt lại aspect là MethodBeforeAdvice.
public class DemoBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before method: " + method.getName());
}
}
Code language: PHP (php)
aplicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.hdd.HelloWorld" />
<bean id="demoBeforeAdvice" class="com.hdd.DemoBeforeAdvice" />
<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="hello" />
<property name="interceptorNames">
<list>
<value>demoBeforeAdvice</value>
</list>
</property>
</bean>
</beans>
Code language: HTML, XML (xml)
target object sẽ là đối tượng HelloWorld.
Demo:
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloWorld = (HelloWorld) context.getBean("helloProxy");
helloWorld.method1();
helloWorld.method2();
}
Code language: JavaScript (javascript)
Output:
before method: method1
-------------------------------------
method 1
-------------------------------------
method 2
Tương tự tôi sẽ tạo các proxy thực hiện cài đặt After returning advice, After throwing adivce, Around advice:
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class DemoAfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("after method: " + method.getName());
}
}
Code language: JavaScript (javascript)
import org.springframework.aop.ThrowsAdvice;
public class DemoThrowAdvice implements ThrowsAdvice {
public void afterThrowing(IllegalArgumentException e) throws Throwable {
System.out.println("throw advice method: " );
}
}
Code language: PHP (php)
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class DemoAroundAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// same with MethodBeforeAdvice
System.out.println("around - before method: " + invocation.getMethod().getName());
try {
// proceed to original method call
Object result = invocation.proceed();
// same with AfterReturningAdvice
System.out.println("around - before method: " + invocation.getMethod().getName());
return result;
} catch (IllegalArgumentException e) {
// same with ThrowsAdvice
System.out.println("around - throw advice method: " + invocation.getMethod().getName());
throw e;
}
}
}
Code language: JavaScript (javascript)
applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.hdd.HelloWorld" />
<bean id="demoBeforeAdvice" class="com.hdd.DemoBeforeAdvice" />
<bean id="demoAfterAdvice" class="com.hdd.DemoAfterAdvice" />
<bean id="demoThrowAdvice" class="com.hdd.DemoThrowAdvice" />
<bean id="demoAroundAdvice" class="com.hdd.DemoAroundAdvice" />
<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="hello" />
<property name="interceptorNames">
<list>
<value>demoBeforeAdvice</value>
<value>demoAfterAdvice</value>
<value>demoThrowAdvice</value>
<value>demoAroundAdvice</value>
</list>
</property>
</bean>
</beans>
Code language: HTML, XML (xml)
Demo:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloWorld = (HelloWorld) context.getBean("helloProxy");
helloWorld.method1();
System.out.println("\n");
helloWorld.method2();
System.out.println("\n");
helloWorld.method3();
}
}
Code language: JavaScript (javascript)
Output:
before method: method1
around - before method: method1
-------------------------------------
method 1
around - before method: method1
after method: method1
before method: method2
around - before method: method2
-------------------------------------
method 2
around - before method: method2
after method: method2
before method: method3
around - before method: method3
-------------------------------------
method 3
around - throw advice method: method3
throw advice method:
Exception in thread "main" java.lang.IllegalArgumentException
Code language: PHP (php)
Tổng kết
Vì AOP là cái bổ sung cho những thiếu sót của OOP, AOP không dành cho những bạn mới bắt đầu lập trình. Spring Framework mặc dù triển khai AOP đơn giản hơn so với AspectJ, cũng khác phức tạp với rất nhiều chức năng có thể dùng đuợc, và nguời viết chỉ tóm tắt 1 chức năng phổ biến nhất của nó là declarative transaction. Dù sao thì bạn vẫn cần tham khảo những tài liệu huớng dẫn về Spring truớc khi có thể dùng nó 1 cách hữu hiệu. Chúc bạn may mắn 😉.
Các bài viết liên quan:
https://hocspringboot.net/2021/08/09/orm-la-gi-tong-quan-ve-orm-framework-2/
https://hocspringboot.net/2021/08/03/gioi-thieu-ve-spring-data-jpa/
Leave a Reply