Spring AOP 01_初始AOP 及兩種動態代理方法
阿新 • • 發佈:2022-05-15
一、Spring AOP簡介
AOP的全稱是Aspect-Oriented Programming,即面向切面程式設計(也稱面向方面程式設計)。它是面向物件程式設計(OOP)的一種補充,目前已成為一種比較成熟的程式設計方式。
在傳統的業務處理程式碼中,通常都會進行事務處理、日誌記錄等操作。雖然使用OOP可以通過組合或者繼承的方式來達到程式碼的重用,但如果要實現某個功能(如日誌記錄),同樣的程式碼仍然會分散到各個方法中。這樣,如果想要關閉某個功能,或者對其進行修改,就必須要修改所有的相關方法。這不但增加了開發人員的工作量,而且提高了程式碼的出錯率。
為了解決這一問題,AOP思想隨之產生。AOP採取橫向抽取機制,將分散在各個方法中的重複程式碼提取出來,然後在程式編譯或執行時,再將這些提取出來的程式碼應用到需要執行的地方。這種採用橫向抽取機制的方式,採用傳統的OOP思想顯然是無法辦到的,因為OOP只能實現父子關係的縱向的重用。雖然AOP是一種新的程式設計思想,但卻不是OOP的替代品,它只是OOP的延伸和補充。
類與切面的關係
AOP的使用,使開發人員在編寫業務邏輯時可以專心於核心業務,而不用過多的關注於其他業務邏輯的實現,這不但提高了開發效率,而且增強了程式碼的可維護性。
AOP術語
Proxy(代理):將通知應用到目標物件之後,被動態建立的物件。
Weaving(織入):將切面程式碼插入到目標物件上,從而生成代理物件的過程。
二、動態代理
- JDK動態代理
JDK動態代理是通過java.lang.reflect.Proxy 類來實現的,我們可以呼叫Proxy類的newProxyInstance()方法來建立代理物件。對於使用業務介面的類,Spring預設會使用JDK動態代理來實現AOP。
案例
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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.example</groupId> <artifactId>Spring_AOP</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.5.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.3</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency> </dependencies> </project>
一、靜態代理
1. 建構函式方法給代理物件賦值
介面類UserDao
public interface UserDao {
public void addUser();
public void deleteUser();
}
實現類UserDaoImpl
import sse.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("add user!");
}
@Override
public void deleteUser() {
System.out.println("delete user!");
}
}
代理類UserDaoProxy
import sse.dao.UserDao;
import sse.dao.impl.UserDaoImpl;
//模擬日誌
public class UserDaoProxy implements UserDao {
private UserDao target;
public UserDaoProxy(UserDao target) { //建構函式方法給代理物件賦值
this.target = target;
}
@Override
public void addUser() {
System.out.println("開始新增使用者");
target.addUser();
System.out.println("完成新增使用者");
}
@Override
public void deleteUser() {
System.out.println("開始刪除使用者");
target.deleteUser();
System.out.println("完成刪除使用者");
}
}
2. set方法
介面類BookDao
public interface BookDao {
void addBook();
}
實現介面的類BookDaoImpl
import sse.dao.BookDao;
public class BookDaoImpl implements BookDao {
@Override
public void addBook() {
System.out.println("新增書籍");
}
}
靜態代理BookDaoProxy
import sse.dao.BookDao;
public class BookDaoProxy implements BookDao {
private BookDao target;
public void setTarget(BookDao target) { //set方法給代理物件賦值
this.target = target;
}
@Override
public void addBook() {
System.out.println("開始新增書籍");
target.addBook();
System.out.println("完成新增書籍");
}
}
二、jdk動態代理
動態代理類JdkProxy
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//通用代理類
public class JdkProxy implements InvocationHandler {
private Object target;//通用代理類,既可以代理UserDao,也可以代理BookDao
public JdkProxy(Object target) {
this.target = target;
}
/*
* invoke方法在反射機制中用到,它可以根據方法名動態地呼叫不同的方法,有可能呼叫addUser(),也有可能呼叫addBook(),我們把它們組合到invoke()方法裡面
* 在invoke方法裡我們通過引數呼叫實際的方法(具體的方法是通過引數傳進來的)
* 通過method.invoke()傳進來的有可能是addUser(),也可能是addBook(),方法裡面有兩個引數,一個是呼叫的target,一個是其引數
* * */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName()+"被呼叫前");
Object ret = method.invoke(target,args);
System.out.println(method.getName()+"被呼叫後");
return ret;
}
}
- 測試1
- 測試2