在Spring AOP中獲取Advised方法信息
1.簡介
在本教程中,我們將向您展示如何使用Spring AOP方面獲取有關方法的簽名,參數和註釋的所有信息。
2. Maven依賴
讓我們從pom.xml
添加Spring Boot AOP Starter庫依賴關係開始:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
3.創建切入點註解
讓我們創建一個AccountOperation
批註。為了澄清,我們將其用作切入點:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccountOperation {
String operation();
}
請注意,創建註釋對於定義切入點不是強制性的。換句話說,我們可以使用Spring AOP提供的切入點定義語言來定義其他切入點類型,例如類中的某些方法,以某些前綴開頭的方法等。
4.創建示例服務
4.1。帳戶類別
讓我們創建一個帶有accountNumber
和balance
屬性的Account
POJO。我們將其用作服務方法中的方法參數:
public class Account {
private String accountNumber;
private double balance;
// getter / setters / toString
}
4.2。服務等級
現在,讓我們使用兩個用@AccountOperation
批註進行批註的方法來創建BankAccountService
類,以便我們可以獲取方面的方法信息。請注意, withdraw
方法將引發一個已檢查的異常WithdrawLimitException
以演示如何獲取有關方法拋出的異常的信息。
另外,請注意, getBalance
方法沒有AccountOperation
批註,因此它不會被方面攔截:
@Component
public class BankAccountService {
@AccountOperation(operation = "deposit")
public void deposit(Account account, Double amount) {
account.setBalance(account.getBalance() + amount);
}
@AccountOperation(operation = "withdraw")
public void withdraw(Account account, Double amount) throws WithdrawLimitException {
if(amount > 500.0) {
throw new WithdrawLimitException("Withdraw limit exceeded.");
}
account.setBalance(account.getBalance() - amount);
}
public double getBalance() {
return RandomUtils.nextDouble();
}
}
5.定義我們的方面
讓我們創建一個BankAccountAspect
以從BankAccountService:
調用的相關方法中獲取所有必要的信息BankAccountService:
@Aspect
@Component
public class BankAccountAspect {
@Before(value = "@annotation(com.baeldung.method.info.AccountOperation)")
public void getAccountOperationInfo(JoinPoint joinPoint) {
// Method Information
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
System.out.println("full method description: " + signature.getMethod());
System.out.println("method name: " + signature.getMethod().getName());
System.out.println("declaring type: " + signature.getDeclaringType());
// Method args
System.out.println("Method args names:");
Arrays.stream(signature.getParameterNames())
.forEach(s -> System.out.println("arg name: " + s));
System.out.println("Method args types:");
Arrays.stream(signature.getParameterTypes())
.forEach(s -> System.out.println("arg type: " + s));
System.out.println("Method args values:");
Arrays.stream(joinPoint.getArgs())
.forEach(o -> System.out.println("arg value: " + o.toString()));
// Additional Information
System.out.println("returning type: " + signature.getReturnType());
System.out.println("method modifier: " + Modifier.toString(signature.getModifiers()));
Arrays.stream(signature.getExceptionTypes())
.forEach(aClass -> System.out.println("exception type: " + aClass));
// Method annotation
Method method = signature.getMethod();
AccountOperation accountOperation = method.getAnnotation(AccountOperation.class);
System.out.println("Account operation annotation: " + accountOperation);
System.out.println("Account operation value: " + accountOperation.operation());
}
}
請注意,我們將切入點定義為註釋,因此BankAccountService
的getBalance
方法未使用AccountOperation,
註釋AccountOperation,
因此方面將不會對其進行攔截。
現在,讓我們詳細分析方面的每個部分,並查看調用BankAccountService
方法時在控制台中得到的內容。
5.1。獲取有關方法簽名的信息
為了獲得我們的方法簽名信息,我們需要從JoinPoint
對像中檢索MethodSignature
:
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
System.out.println("full method description: " + signature.getMethod());
System.out.println("method name: " + signature.getMethod().getName());
System.out.println("declaring type: " + signature.getDeclaringType());
現在讓我們調用服務的withdraw()
方法:
@Test
void withdraw() {
bankAccountService.withdraw(account, 500.0);
assertTrue(account.getBalance() == 1500.0);
}
運行withdraw()
測試後,我們現在可以在控制台上看到以下結果:
full method description: public void com.baeldung.method.info.BankAccountService.withdraw(com.baeldung.method.info.Account,java.lang.Double) throws com.baeldung.method.info.WithdrawLimitException
method name: withdraw
declaring type: class com.baeldung.method.info.BankAccountService
5.2。獲取有關參數的信息
要檢索有關方法參數的信息,我們可以使用MethodSignature
對象:
System.out.println("Method args names:");
Arrays.stream(signature.getParameterNames()).forEach(s -> System.out.println("arg name: " + s));
System.out.println("Method args types:");
Arrays.stream(signature.getParameterTypes()).forEach(s -> System.out.println("arg type: " + s));
System.out.println("Method args values:");
Arrays.stream(joinPoint.getArgs()).forEach(o -> System.out.println("arg value: " + o.toString()));
讓我們通過調用BankAccountService
的deposit
方法來嘗試:
@Test
void deposit() {
bankAccountService.deposit(account, 500.0);
assertTrue(account.getBalance() == 2500.0);
}
這是我們在控制台上看到的:
Method args names:
arg name: account
arg name: amount
Method args types:
arg type: class com.baeldung.method.info.Account
arg type: class java.lang.Double
Method args values:
arg value: Account{accountNumber='12345', balance=2000.0}
arg value: 500.0
5.3。獲取有關方法註釋的信息
我們可以使用Method
類的getAnnotation()
方法獲取有關註釋的信息:
Method method = signature.getMethod();
AccountOperation accountOperation = method.getAnnotation(AccountOperation.class);
System.out.println("Account operation annotation: " + accountOperation);
System.out.println("Account operation value: " + accountOperation.operation());
現在,讓我們重新運行withdraw()
測試並檢查我們得到了什麼:
Account operation annotation: @com.baeldung.method.info.AccountOperation(operation=withdraw)
Account operation value: withdraw
5.4。獲取其他信息
我們可以獲得有關我們方法的其他信息,例如它們的返回類型,它們的修飾符以及它們拋出的異常(如果有):
System.out.println("returning type: " + signature.getReturnType());
System.out.println("method modifier: " + Modifier.toString(signature.getModifiers()));
Arrays.stream(signature.getExceptionTypes())
.forEach(aClass -> System.out.println("exception type: " + aClass));
現在讓我們創建一個新的withdrawWhenLimitReached
測試,該測試使withdraw()
方法超出其定義的提現限制:
@Test
void withdrawWhenLimitReached()
{
Assertions.assertThatExceptionOfType(WithdrawLimitException.class)
.isThrownBy(() -> bankAccountService.withdraw(account, 600.0));
assertTrue(account.getBalance() == 2000.0);
}
現在檢查控制台輸出:
returning type: void
method modifier: public
exception type: class com.baeldung.method.info.WithdrawLimitException
我們的最後一個測試將有助於演示getBalance()
方法。如前所述,它不會被方面攔截,因為方法聲明中沒有AccountOperation
批註:
@Test
void getBalance() {
bankAccountService.getBalance();
}
運行此測試時,控制台中沒有輸出,正如我們期望的那樣。
六,結論
在本文中,我們了解瞭如何獲取有關使用Spring AOP方面的方法的所有可用信息。為此,我們定義了一個切入點,將信息打印到控制台中,並檢查運行測試的結果。