Spring : AOP with Java Config - Parameter Pattern Wildcards
1. 이 포스트는 Spring AOP with Java Config 의 연장이다.
2. 포인트 컷 정의에서 parameter에 들어갈 pattern을 wildcard를 통해 지정할 수 있다.
2-1 () parameter가 없는 메소드 정의
2-2 (*) 하나의 parameter를 받는데 모든 타입을 다 허용한다.
2-3 (..) 어떤 타입의 parameter형태도 다 허용한다.
3. 각 wild 카드에 해당하는 예제들
3-1 모든 리턴 타입을 허용하는 add로 시작하고 parameter가 없는 메소드를 허용하는 예제
3-1-1 이미 바로 전 포스트에서 보여 주었다.
// AOP Advice 클래스
@Aspect
@Component
public class LoggingAspect {
// @Before(value = "execution(public void addAccount())")
// @Before(value = "execution(public void add*())")
// @Before(value="execution(boolean add*())")
@Before(value="execution(* add*())")
public void beforeAddAccountAdvice() {
System.out.println("\nExecuting @Before advice on * add*()");
}
}
// main 클래스
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JavaConfig.class);
AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);
accountDAO.addAccount();
Account account = new Account();
accountDAO.addAccount(account);
MembershipDAO membershipDAO = context.getBean("membershipDAO", MembershipDAO.class);
membershipDAO.addAccount();
membershipDAO.addGoodAccount();
context.close();
}
}
// dummy component 1
@Component
public class AccountDAO {
public void addAccount() {
System.out.println(getClass() + ": with No Parameter Doing my DB work: Adding an account\n");
}
public void addAccount(Account account) {
System.out.println(getClass() + ": with Account Parameter. Doing my DB work: Adding an account\n");
}
}
// dummy component 2
@Component
public class MembershipDAO {
public void addAccount() {
System.out.println(getClass() + ": Doing my DB work: Adding an account\n");
}
public void addGoodAccount() {
System.out.println(getClass() + ": Doing my DB work: Adding a good account\n");
}
}
// 결과
Executing @Before advice on * add*()
class pe.pilseong.spring_aop_review.dao.AccountDAO: with No Parameter Doing my DB work: Adding an account
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account Parameter. Doing my DB work: Adding an account
Executing @Before advice on * add*()
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding an account
Executing @Before advice on * add*()
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding a good account
3-2 모든 리턴 타입을 허용하는 한 개의 특정한 타입의 parameter를 허용하는 예제
3-2-1 반드시 parameter type에는 패키지 경로를 포함하는 fully qualified name을 사용해야 한다.
3-2-2 그렇지 않으면 class type을 찾을 수 없다고 IllegalArgumentException이 발생한다.
@Aspect
@Component
public class LoggingAspect {
// @Before(value = "execution(public void addAccount())")
// @Before(value = "execution(public void add*())")
// @Before(value="execution(boolean add*())")
// @Before(value="execution(* add*())")
@Before(value="execution(* add*(pe.pilseong.spring_aop_review.Account))")
public void beforeAddAccountAdvice() {
System.out.println("\nExecuting @Before advice on * add*(Account)");
}
}
// 결과
class pe.pilseong.spring_aop_review.dao.AccountDAO: with No Parameter Doing my DB work: Adding an account
Executing @Before advice on * add*(Account)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account Parameter. Doing my DB work: Adding an account
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding an account
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding a good account
3-3 '..' wildcard의 활용
3-3-1 Account와 boolean을 받는 메소드를 추가하고 우선 3-2의 경우로 실행하면 아래와 같은 결과가 나온다.
3-3-2 당연히 Account를 파라메터로 받는 메소드만 Advice가 실행됨을 알 수 있다.
@Component
public class AccountDAO {
public void addAccount() {
System.out.println(getClass() + ": with No Parameter Doing my DB work: Adding an account\n");
}
public void addAccount(Account account) {
System.out.println(getClass() + ": with Account Parameter. Doing my DB work: Adding an account\n");
}
// 추가 메소드
public void addAccount(Account account, boolean flag) {
System.out.println(getClass() + ": with Account, boolean Parameter. Doing my DB work: Adding an account\n");
}
}
// 메인 클래스
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JavaConfig.class);
AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);
accountDAO.addAccount();
Account account = new Account();
accountDAO.addAccount(account);
// 추가한 메소드 call
accountDAO.addAccount(account, true);
MembershipDAO membershipDAO = context.getBean("membershipDAO", MembershipDAO.class);
membershipDAO.addAccount();
membershipDAO.addGoodAccount();
context.close();
}
}
// 결과
class pe.pilseong.spring_aop_review.dao.AccountDAO: with No Parameter Doing my DB work: Adding an account
Executing @Before advice on * add*(Account)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account Parameter. Doing my DB work: Adding an account
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account, boolean Parameter. Doing my DB work: Adding an account
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding an account
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding a good account
3-3-2 Account 파라메터 옆에 '..' 와일드 카드를 추가한 경우
3-3-2-1 Account를 받는 것 뿐만 아니라 Account, boolean을 받는 메소드도 @Before advice가 실행되었다.
@Aspect
@Component
public class LoggingAspect {
// @Before(value = "execution(public void addAccount())")
// @Before(value = "execution(public void add*())")
// @Before(value="execution(boolean add*())")
// @Before(value="execution(* add*())")
// @Before(value="execution(* add*(pe.pilseong.spring_aop_review.Account))")
@Before(value="execution(* add*(pe.pilseong.spring_aop_review.Account, ..))")
public void beforeAddAccountAdvice() {
System.out.println("\nExecuting @Before advice on * add*(Account)");
}
}
// 결과
class pe.pilseong.spring_aop_review.dao.AccountDAO: with No Parameter Doing my DB work: Adding an account
Executing @Before advice on * add*(Account, ..)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account Parameter. Doing my DB work: Adding an account
Executing @Before advice on * add*(Account, ..)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account, boolean Parameter. Doing my DB work: Adding an account
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding an account
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding a good account
3-3-3 파라메터로 '..' 와일드 카드만 설정한 경우 - 모든 형태의 parameter 허용
3-3-3 파라메터 형태와 무관하게 add로 시작하는 모든 메소드 실행 전에 @Before Advice가 실행되었다.
@Aspect
@Component
public class LoggingAspect {
// @Before(value = "execution(public void addAccount())")
// @Before(value = "execution(public void add*())")
// @Before(value="execution(boolean add*())")
// @Before(value="execution(* add*())")
// @Before(value="execution(* add*(pe.pilseong.spring_aop_review.Account))")
// @Before(value="execution(* add*(pe.pilseong.spring_aop_review.Account, ..))")
@Before(value="execution(* add*(..))")
public void beforeAddAccountAdvice() {
System.out.println("\nExecuting @Before advice on * add*(..)");
}
}
// 실행 결과
Executing @Before advice on * add*(..)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with No Parameter Doing my DB work: Adding an account
Executing @Before advice on * add*(..)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account Parameter. Doing my DB work: Adding an account
Executing @Before advice on * add*(..)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account, boolean Parameter. Doing my DB work: Adding an account
Executing @Before advice on * add*(..)
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding an account
Executing @Before advice on * add*(..)
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding a good account
3.4 패키지를 한정 하는 방법
3-4-1 아래 소스처럼 패키지 이름을 명시하고 클래스와 메소드 이름에 '*'를 사용하면
3-4-2 해당 패키지에 포함된 모든 메소드 실행시 @Before advice가 실행된다.
@Aspect
@Component
public class LoggingAspect {
// @Before(value = "execution(public void addAccount())")
// @Before(value = "execution(public void add*())")
// @Before(value="execution(boolean add*())")
// @Before(value="execution(* add*())")
// @Before(value="execution(* add*(pe.pilseong.spring_aop_review.Account))")
// @Before(value="execution(* add*(pe.pilseong.spring_aop_review.Account, ..))")
// @Before(value="execution(* add*(..))")
@Before("execution(* pe.pilseong.spring_aop_review.dao.*.*(..))")
public void beforeAddAccountAdvice() {
System.out.println("\nExecuting @Before advice on pe.pilseong.spring_aop_review.dao.*.*(..)");
}
}
3-4-3 아래처럼 MembershipDAO에 addAccount가 아닌 이름의 메소드를 추가하였다.
@Component
public class MembershipDAO {
public void addAccount() {
System.out.println(getClass() + ": Doing my DB work: Adding an account\n");
}
public void addGoodAccount() {
System.out.println(getClass() + ": Doing my DB work: Adding a good account\n");
}
// 추가된 메소드
public void membership() {
System.out.println(getClass() + ": Doing my DB work: membership method is doing something \n");
}
}
3-4-4 메인 클래스에 추가한 메소드를 실행하도록 변경 후 실행
3-4-4-1 pe.pilseong.spring_aop_review.dao 패키지에 포함된 모든 클래스의 메소드를 호출하기 전
3-4-4-2 @Before advice가 실행 된다.
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JavaConfig.class);
AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);
accountDAO.addAccount();
Account account = new Account();
accountDAO.addAccount(account);
accountDAO.addAccount(account, true);
MembershipDAO membershipDAO = context.getBean("membershipDAO", MembershipDAO.class);
membershipDAO.addAccount();
membershipDAO.addGoodAccount();
// 추가로 호출한 부분
membershipDAO.membership();
context.close();
}
}
// 결과
Executing @Before advice on pe.pilseong.spring_aop_review.dao.*.*(..)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with No Parameter Doing my DB work: Adding an account
Executing @Before advice on pe.pilseong.spring_aop_review.dao.*.*(..)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account Parameter. Doing my DB work: Adding an account
Executing @Before advice on pe.pilseong.spring_aop_review.dao.*.*(..)
class pe.pilseong.spring_aop_review.dao.AccountDAO: with Account, boolean Parameter. Doing my DB work: Adding an account
Executing @Before advice on pe.pilseong.spring_aop_review.dao.*.*(..)
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding an account
Executing @Before advice on pe.pilseong.spring_aop_review.dao.*.*(..)
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: Adding a good account
Executing @Before advice on pe.pilseong.spring_aop_review.dao.*.*(..)
class pe.pilseong.spring_aop_review.dao.MembershipDAO: Doing my DB work: membership method is doing something