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.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方面的方法的所有可用信息。为此,我们定义了一个切入点,将信息打印到控制台中,并检查运行测试的结果。
0 评论