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. Pointcut 어노테이션 만들기
AccountOperation 어노테이션을 만들어 보겠습니다 . 명확히하기 위해, 우리의 관점에서 포인트 컷으로 사용할 것입니다 :
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccountOperation {
String operation();
}
포인트 컷을 정의하기 위해 어노테이션 생성은 필수가 아닙니다. 즉, Spring AOP에서 제공하는 포인트 컷 정의 언어를 사용하여 클래스의 특정 메소드, 일부 접두어로 시작하는 메소드 등과 같은 다른 포인트 컷 유형을 정의 할 수 있습니다.
4. 예제 서비스 만들기
4.1. Account class
accountNumber 및 잔액 속성을 사용하여 계정 POJO를 생성 해 보겠습니다 . 서비스 메서드에서 메서드 인수로 사용합니다.
public class Account {
private String accountNumber;
private double balance;
// getter / setters / toString
}
4.2. Service class
이제 우리 측면에서 메서드의 정보를 얻을 수 있도록 @AccountOperation 어노테이션으로 어노테이션을 다는 두 가지 메서드를 사용하여 BankAccountService 클래스를 만들어 보겠습니다 . (가) 주 철회 방법은 체크 예외가 발생 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. Aspect 정의
BankAccountService 에서 호출 된 관련 메서드에서 필요한 모든 정보를 가져 오기 위해 BankAccountAspect 를 만들어 보겠습니다 .
@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());
}
}
Pointcut을 어노테이션으로 정의 했으므로 BankAccountService 의 getBalance 메서드 가 AccountOperation으로 어노테이션 처리 되지 않았으므로 aspect는이를 가로 채지 않습니다.
이제 측면의 각 부분을 자세히 분석하고 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 에서 입금 방법 을 호출하여이를 시도해 보겠습니다 .
@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. 추가 정보 얻기
반환 유형, 수정 자 및 throw하는 예외 (있는 경우)와 같은 메서드에 대한 추가 정보를 얻을 수 있습니다.
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));
이제 withdraw () 메서드가 정의 된 인출 제한을 초과 하도록 만드는 새 테스트 withdrawWhenLimitReached 를 생성 해 보겠습니다 .
@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 어노테이션 이 없기 때문에 aspect에서 가로 채지 않습니다 .
@Test
void getBalance() {
bankAccountService.getBalance();
}
이 테스트를 실행할 때 예상대로 콘솔에 출력이 없습니다.
6. 결론
이 기사에서 우리는 Spring AOP 측면을 사용하여 메소드에 대해 사용 가능한 모든 정보를 얻는 방법을 보았다. 포인트 컷을 정의하고, 정보를 콘솔에 출력하고, 테스트 실행 결과를 확인함으로써 그렇게했습니다.