Understanding Spring AOP

AOP là gì và tại sao lại dùng AOP

Chúng ta đã quá quen thuộc với khái niệm OOP "lập trình hướng đối tượng". Vậy AOP là gì? mục đích của AOP là như thế nào? AOP là từ viết tắt của Aspect Oriented Programing " Ngôn ngữ hướng khía cạnh" AOP phát triển dựa trên OOP chứ không phải ra đời nhằm thay thế OOP, đó là phần bổ sung cho OOP khi mà có những việc với cách làm việc theo OOP không giải quyết được vấn đề. Chúng ta đã biết OOP module hóa dựa trên class, phân chia đối tượng dưa theo hành vi. Thế nhưng có những việc như việc gọi lại chức năng nào đó ở các thời điểm khác nhau. Điển hình như việc quản lý Transaction. Chúng ta có thể hiểu nôm na OOP là việc module hóa dựa theo "Khía cạnh" khi đó nó sẽ tạo là một đối tượng mà có thể kết nối xuyên suốt với các class khác.

Các Core Concept của AOP

Aspect

Một Aspect là một class mà nó có thể cắt xuyên qua nhiều class, ví dụ như Transaction Management. Chúng ta có thể tạo ra class Aspect bắng cách thông thường là config trong XML hoặc là dùng @Aspect annotation. Đây chính là class mà chúng ta muốn tạo ra, và nó sẽ được liên kết với các class khác trong project tùy theo cách implement của mình.

JoinPoint

Việc Class Aspect liên kết với các class khác thì sẽ bằng cách nào. JoinPoint là một phần trong đó, với mỗi class thì sẽ có các function, thì những function mà sẽ được dùng để liên kết với class Aspect chính là các joinpoint

Advice

Khi mà class Aspect liên kết với các class khác thì chắc chắc nó sẽ thực thì một việc gì đó tương ứng với khi một liên kết tới JoinPoint được thực hiên.

PointCut

Ở các concept trên ta có thế hình dung đơn giản như sau. 1 Class Aspect nó sẽ có các function ở tại class đó ( chính là các Advice) và nó muốn liên kết với các class khác bằng cách thông qua việc liên kết tới các function ở các class đó ( Chính là các JoinPoint). Nhưng làm cách nào để có thể liên kết tới được các JointPoint? Thì PointCut sẽ thực hiện công việc này. PointCut thực ra chính là các biếu thức, nó giống như là một câu lệnh để cho chương trình hiểu việc nó muốn liên kết tới class nào, function nào.

Một số kiểu Advice trong AOP

Before Advice

Những advice này sẽ được chạy trước khi thực thi các JointPoint method

After (finally) Advice

Nó giống như finally trong try catch vậy. Tức là sau khi các JointPoint method được thực thi, bất kế nó có thành công, hay bị exception thì cuối cùng các advice này vẫn được chạy qua.

After Returning Advice

Trong trường hợp chúng ta chỉ muốn thực hiên advice sau khi các JoinPoint thực thi bình thường, không bị lỗi exception thì sẽ dùng tới loại advice này.

After Throwing Advice

Tương tự ở trên nhưng trường hợp này chúng ta chỉ thực hiện advice sau khi các JointPoint thực thi mà throw ra exception.

Around Advice

Đây là loại Advice quan trọng nhất cũng như mạnh mẽ nhất. Advice này sẽ được thực thi bao quanh JoiPoint, khi đó chúng ta có thể đưa ra quyết định có thực thi JoinPoint hay không. Chúng ta cũng có thể viết code để cho advice có thể chạy trước hoặc sau JoinPoint tùy thích. Có thể nói nó có chức năng của tất cả các loại Advice khác có thể làm được.

Spring AOP Example

AOP AspectJ Dependencies

Ở đây chúng ta sẽ sử dụng aspectjrt và aspectjtools để cung cấp các annotation cần thiết

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.springframework.samples</groupId>
	<artifactId>SpringAOPExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>4.0.2.RELEASE</spring-framework.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

		<!-- Test -->
		<junit.version>4.11</junit.version>

		<!-- AspectJ -->
		<aspectj.version>1.7.4</aspectj.version>

	</properties>

	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- AspectJ dependencies -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${aspectj.version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjtools</artifactId>
			<version>${aspectj.version}</version>
		</dependency>
	</dependencies>
</project>

Normal Class

@Entity
public class NormalClass {
	
	public Employee joinPointMethod(){
		// do things in JoinPoint method
	}
}

Aspect Class

@Aspect
public class EmployeeAspect {

	@Before("execution(public String joinPointMethod())")
	public void executeBeforeAdviceWhenDoJointPointMethod(){
		// do things on Advice method
	}
	
	@Before("execution(* pacage.*.get*())")
	public void executeBeforeAdviceWhenDoAnyMethodInPackage(){
		// Thực hiện advice khi bất kỳ function nào trong package được chỉ định execute
	}
    
    Tương tự cho các advice khác cũng có cấu trúc tương tự
}