1.简介
在本教程中,我们将向您展示如何使用Spring AOP方面获取有关方法的签名,参数和注释的所有信息。
2. Maven依赖
让我们从pom.xml添加Spring Boot AOP Starter库依赖关系开始:
<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-aopartifactId> 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.05.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方面的方法的所有可用信息。为此,我们定义了一个切入点,将信息打印到控制台中,并检查运行测试的结果。
0 评论