ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 6장) 6.5 스프링 AOP
    Java & Spring/토비의 스프링 3.1 2021. 7. 23. 15:52
    반응형

    6장 AOP

    • 부가기능 적용 후에 기존 설계 코드에 영향을 주지 않도록 제공돼야 함
      • 다른 코드에서는 존재가 보이지 않지만, 메소드가 호출되는 과정에서 다이내믹하게 부가적인 기능을 제공

    6.5.1 자동 프록시 생성

    • 타깃 오브젝트마다 비슷한 내용의 ProxyFactoryBean 설정 정보 추가 부분이 남은 해결 과제
    • 중복 문제의 접근 방법
      • JDBC API를 사용하는 DAO 코드
        • 전략 패턴과 DI를 적용해서 템플릿과 콜백, 클라이언트로 나누어 해결
      • 반복적인 위임 코드가 필요한 프록시 클래스 코드
        • 다이내믹 프록시와 다이내믹 프록시 생성 팩토리 DI를 사용해서 런타임 코드 자동생성 기법으로 해결
      • 반복적인 ProxyFactoryBean 설정
        • 미해결
    • 빈 후처리기를 이용한 자동 프록시 생성기
      • 스프링은 컨테이너로서 제공하는 기능 중 변하지 않는 핵심 부분 외에는 대부분 확장할 수 있는 확장 포인트를 제공
        • BeanPostProcessor 인터페이스를 구현해서 만드는 빈 후처리기 존재
        • DefaultAdvisorAutoProxyCreator 빈 후처리기 이용
          • 어드바이저를 이용한 자동 프록시 생성기
          • 빈 후처리기 자체를 빈으로 등록하여 스프링에 적용
            • 빈 오브젝트가 생성될 때마다 빈 후처리기에 보내서 후처리 작업 요청
            • 프로퍼티 강제 수행 및 초기화 작업 수행, 만들어진 빈 오브젝트 자체를 바꿀 수 있음
              • 스프링이 설정을 참고해서 만든 오브젝트가 아닌 다른 오브젝트를 빈으로 등록 가능
          • 빈 오브젝트의 일부를 프록시로 포장하고 프록시를 빈으로 등록 ~> 자동 프록시 생성 빈 후처리기
        • DefaultAdvisorAutoProxyCreator 빈 후처리기 등록
          ~> 빈 오브젝트를 만들 때마다 후처리기에 빈을 보냄
          ~> 빈으로 등록된 모든 어드바이저 내의 포인트컷으로 프록시 적용 대상인지 확인
          ~> 내장된 프록시 생성기에게 현재 빈에 대한 프록시를 만들게 하고, 어드바이저를 연결
          ~> 프록시가 생성되면 프록시 오브젝트를 컨테이너에 반환
          ~> 컨테이너는 이 프록시 오브젝트를 빈으로 등록하고 사용
    • 확장된 포인트컷
      • 포인트컷은 메소드 선정과 빈 오브젝트 자체 선정 기능 두 가지 기능을 가짐
      • public interface Pointcut {
            ClassFilter getClassFilter(); // 프록시 적용할 클래스인지 확인
            MethodMatcher getMethodMatcher(); // 어드바이스를 적용할 메소드인지 확인
        }
        • 프록시를 적용할 클래스인지 판단 ~> 어드바이스를 적용할 메소드인지 확인
        • ProxyFactoryBean에서는 클래스 레벨 필터가 필요 없었지만, 모든 빈에 대해 프록시 자동 적용 대상을 선별하는 빈 후처리기 DefaultAdvisorAutoProxyCreator는 클래스와 메소드 선정 알고리즘 모두 가지고 있는 포인트컷이 필요
          • 위의 포인트컷 + 어드바이스가 결합된 어드바이저가 등록되어 있어야함
    • 포인트컷 테스트
      • @Test
        public void classNamePointcutAdvisor() {
            NameMatcherPointcut classMethodPointcut = new NameMatcherMethodPointcut() {
                public ClassFilter getClassFilter() {
                    return new ClassFilter() {
                        public boolean matches(Class<?> clazz) {
                            return clazz.getSimpleName().startsWith("HelloT"); // HelloT로 시작하는 클래스를 선정
                        }
                    };
                }
            };
            classMethodPointcut.setMappedName("sayH*"); // sayH로 시작하는 메소드 선정
        
            // Test
            checkAdviced(new HelloTarget(), classMethodPointcut, true);
            checkAdviced(new HelloWorld(), classMethodPointcut, false;)
        }
        
        private void checkAdviced(Object target, Pointcut pointcut, boolean adviced) {
            ProxyFactoryBean pfBean = new ProxyFactoryBean();
            pfBean.setTarget(target);
            pfBean.addAdvisor(new DefaultPointcutAdvisor(pointcut, new UppercaseAdvice()));
            Hello proxiedHello = (Hello) pfBean.getObject();
        
            if (adviced) {
                assetThat(proxiedHello.sayHello("Toby"), is("HELLO TOBY"));
                assetThat(proxiedHello.sayHi("Toby"), is("HI TOBY"));
            } else {
                assetThat(proxiedHello.sayHello("Toby"), is("Hello Toby"));
                assetThat(proxiedHello.sayHi("Toby"), is("Hi Toby"));
            }
        }
      • 포인트 컷이 클래스 필터까지 동작해서 클래스를 거르면, 프록시를 적용해도 부가기능이 제공되지 않음
        • 어차피 어떤 메소드에도 부가기능이 적용되지 않는데, 굳이 프록시를 둘 이유가 없음

    6.5.2 DefaultAdvisorAutoProxyCreator의 적용

    • 클래스 필터를 적용한 포인트컷 작성
      • public class NameMatchClassMethodPointcut extends NameMatchMethodPointcut {
            public void setMappedClassName(String mappedClassName) {
                this.setClassFilter(new SimpleClassFilter(mappedClassName));
            }
        
            static class SimpleClassFilter implements ClassFilter {
                String mappedName;
        
                private SimpleClassFilter(String mappedName) {
                    this.mappedName = mappedName;
                }
        
                @Override
                public boolean matches(Class<?> clazz) {
                    return PatternMatchUtils.simpleMatch(mappedName, clazz.getSimpleName()); // 와일드카드 문자열 비교를 지원
                }
            }
        }
    • 어드바이저를 이용하는 자동 프록시 생성기 등록
      • 다른 빈에서 참조되거나 코드에서 빈 이름으로 조회될 필요가 없기 때문에, id 애트리뷰트는 생략하고 class만 입력하여 사용 가능
    • 포인트컷 등록
      • 프로퍼티에 mapping될 클래스 이름과 메소드 이름의 패턴을 설정
    • 어드바이스와 어드바이저
      • 어드바이스와 어드바이저 모두 설정을 변경할 필요가 없지만, 사용되는 방법이 바뀜
      • DefaultAdvisorAutoProxyCreator에 의해 자동수집되고, 프록시 대상 선정 과정에 참여하며, 자동 생성된 프록시에 다이내믹하게 DI돼서 동작하는 어드바이저가 됨
    • ProxyFactoryBean 제거와 서비스 빈의 원상복구
      • 간접적으로 사용되던 userServiceImpl 빈의 아이디를 userService로 재설정
        • 더 이상 명시적인 프록시 팩토리 빈을 등록하지 않기 때문 ~> ProxyFactoryBean 타입 빈 삭제 가능
    • 자동 프록시 생성기를 사용하는 테스트
      • 강제 예외 발생용 TestUserService 클래스를 빈으로 등록하기
        • 문제점
          • TestUserService가 UserServiceTest 내부에 정의된 스태틱 클래스
            • 스태틱 멤버 클래스를 설정에 등록할 때는, $를 붙여 사용
          • 포인트컷이 트랜잭션 어드바이스를 적용해주는 대상 클래스 이름 패턴에 불일치
            • 클래스 이름을 TestUserServiceImpl로 수정
            • users 리스트에서 예외를 발생시킬 기준 id를 고정 상수값으로 수정
        • userService를 parent로 등록하고, @Autowired를 통해 testUserService를 DI 받도록 수정
    • 자동 생성 프록시 확인
      • 트랜잭션이 필요한 빈에 트랜잭션 부가기능이 적용됐는지 확인
        • 트랜잭션이 커밋되는 경우 적용 여부를 확인하기 힘듦 ~> 예외 상황 롤백에 대한 테스트 필요
      • 아무 빈에나 트랜잭션 부가기능이 적용된 것은 아닌지 확인
        • 프록시 자동생성기가 어드바이저 빈에 연결해둔 포인트컷 클래스 필터를 이용해 원하는 빈에만 프록시를 생성했는지 확인
        • 포인트컷 빈의 클래스 이름 패턴을 변경해서 testUserService 빈에 트랜잭션이 적용되지 않게해서 확인
        • 자동생성된 프록시 확인
          • getBean("userService")로 가져온 오브젝트의 타입은 TestUserService 타입이 아니라 JDK의 Proxy 타입
          • @Test
            public void advisorAutoProxyCreator() {
                assertThat(testUserService, is(Proxy.class));
            }

    6.5.3 포인트컷 표현식을 이용한 포인트컷

    • 스프링의 리플렉션 API 사용
      • 장점
        • 클래스와 메소드 이름, 패키지, 파라미터, 리턴 값, 애노테이션, 구현 인터페이스, 상속 클래스 등의 정보를 쉽게 파악 가능
      • 단점
        • 코드 작성이 번거롭고, 메타정보 비교 방법을 조건이 달라질 때마다 포인트컷 구현 코드를 수정해야함
    • 스프링의 포인트컷 표현식
      • 일종의 표현식 언어로 포인트컷 작성
      • AspectJExpressionPointcut 클래스 사용
        • 포인트컷 표현식을 이용해 클래스와 메소드 선정 알고리즘을 한 번에 지정
        • AspectJ의 일부 문법을 확장해서 사용해서, AspectJ 포인트컷 표현식이라고도 함
      • 포인트컷 테스트용 클래스 생성
        • package springbook.leaningtest.spring.pointcut;
          
          public class Target implements TargetInterface {
              public void hello() {}
              public void hello(String a) {}
              public int minus(int a, int b) throws RuntimeException {return 0;}
              public int plus(int a, int b) {return 0;} // 이상 4개는 override한 메소드
              public void method() {} // 클래스 내부에서 자체 정의한 메소드
          }
    • 포인트컷 표현식 문법
      • 포인트컷 지시자를 이용해서 작성
        • execution()이 대표적으로 사용됨
          • execution([접근제한자 패턴] 타입패턴 [타입패턴.]이름패턴 (타입패턴 | *..*, ...) [throws 예외 패턴])
        • 메소드 시그니처를 이용한 포인트컷 표현식 테스트
          • @Test
            public void methodSignaturePointcut() throws SecurityException, NoSuchMethodException {
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression("execution(public int springbook.learningtest.spring.pointcut.Target.minus(int,int) throws java.lang.RuntimeException)");
            
                // 
            
                .minus()
                assertThat(pointcut.getClassFilter().matches(Target.class) && 
                          pointcut.getMethodMatcher().matches(
                          Target.class.getMethod("minus", int.class, int.class), null), is(true));
            
                // Target.plus()
                assertThat(pointcut.getClassFilter().matches(Target.class) &&
                          pointcut.getMethodMatcher().matches(
                          Target.class.getMethod("plus", int.class, int.class), null), is(false));
            }
    • 포인트컷 표현식 테스트
      • 메소드 시그니처를 사용한 포인트 표현식 중, 접근 제한자 패턴, 클래스 타입 패턴, 예외 패턴은 옵션이기 때문에 생략 가능
        • execution(int minus(int, int))와 같이 간략하게 표현 가능
          • 리턴 타입 제한을 없애고 싶다면, int 대신 * 와일드카드를 적용 가능
          • 파라미터 개수와 타입을 무시하려면, (int, int) 부분을 (...)로 적용 가능
          • 선정 조건을 다 없애고 모든 메소드를 다 허용하는 포인트 컷이라면 execution(* *(..))과 같이 사용 가능
      • 포인트컷과 메소드를 비교해주는 테스트 헬퍼 메소드
        • public void pointcutMatches(String expression, Boolean expected, Class<?> clazz, String methodName, Class<?>... args) throws Exception {
              AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
              pointcut.setExpression(expression);
          
              assertThat(pointcut.getClassFilter().matches(clazz) &&
                        pointcut.getMethodMatcher().matches(clazz.getMethod(methodName, args), null), is(expected));
          }
      • 타깃 클래스의 메소드에 대해 포인트컷 선정 여부 검사 헬퍼 메소드
        • public void targetClassPointcutMatches(String expression, boolean... expected) throws Exception{
              pointcutMatches(expression, expected[0], Target.class, "hello");
                  pointcutMatches(expression, expected[1], Target.class, "hello", String.class);
                  pointcutMatches(expression, expected[2], Target.class, "plus", int.class, int.class);
                  pointcutMatches(expression, expected[3], Target.class, "minus", int.class, int.class);
                  pointcutMatches(expression, expected[4], Target.class, "method");
          }
      • 포인트컷 표현식 테스트
        • @Test
          public void pointcut() throws Exception {
              targetClassPointcutMatches("execution(* *(..))", true, true, true, true, true);
          }
        • Target 클래스 대신 구현 대상인 interface를 선정하게되면, 해당 interface를 구현한 메소드에만 포인트 컷이 적용됨
    • 포인트컷 표현식을 이용하는 포인트컷 적용
      • 표현식
        • execution
          • 메소드의 시그니처 비교
        • bean
          • 스프링 빈의 이름으로 비교
          • 단순한 클래스와 메소드라는 기준을 넘어서는 유용한 선정 방식
        • 특정 애노테이션 타입, 메소드, 파라미터에 적용되어 있는 것을 보고 메소드를 선정하게 하는 포인트 컷도 가능
          • @annotation(Transactional);
      • 포인트컷 적용
        • 앞서 만든 NameMatchclassMethodPointcut과 같이 직접 구현 클래스를 사용하지말고, 포인트컷 표현식을 사용해서 수정
          • AspectJExpressionPointcut으로 빈을 등록하고, 프로퍼티에 mapping될 클래스 이름과 메소드 이름의 패턴을 설정하도록 수정
    • 타입 패턴과 클래스 이름 패턴
      • 단순한 클래스 이름 패턴과 포인트컷 표현식에서 사용하는 타입 패턴의 차이점
        • 포인트컷 표현식의 클래스 이름에 적용되는 패턴은 클래스 이름 패턴이 아니라 타입 패턴이기 때문에, 구현 인터페이스, 슈퍼 클래스, 해당 클래스 모두 적용됨

    6.5.4 AOP란 무엇인가?

    • UserService에 트랜잭션 적용 과정 정리
    • 트랜잭션 서비스 추상화
      • 트랜잭션 경계설정 코드를 비즈니스 로직에 넣으면서 생긴 문제는 특정 트랜잭션 기술에 종속된 코드가 되는 것
        • 서비스 추상화 기법을 적용
        • 구체적인 구현 내용을 담은 의존 오브젝트를 런타임 시에 다이내믹하게 DI
    • 프록시와 데코레이터 패턴
      • 비즈니스 로직 코드에 트랜잭션을 적용하고 있다는 사실이 코드에 드러나 있는 문제
        • DI를 이용한 데코레이터 패턴 적용
          • 클라이언트가 인터페이스와 DI를 통해 접근, 데코레이터 패턴으로 트랜잭션 부가기능 부여
          • 클라이언트가 일종의 프록시 역할을 하는 데코레이터를 거쳐 타깃에 접근
    • 다이내믹 프록시와 프록시 팩토리 빈
      • 트랜잭션 기능을 부여하지 않아도 되는 메소드마저 프록시로서 위임기능이 필요 ~> 프록시 클래스를 일일이 만드는 작업의 부담 & 구현 코드 중복 문제가 존재
      • 프록시 클래스 없이도 프록시 오브젝트를 런타임 시에 만들어주도록 JDK 다이내믹 프록시 적용
        • 동일한 기능의 프록시를 여러 오브젝트에 적용할 경우 오브젝트 단위의 중복 문제는 여전히 존재
      • 프록시 팩토리 빈을 이용해서 다이내믹 프록시 생성에 DI 도입
        • 내부적으로 템플릿/콜백 패턴 활용
          • 어드바이스(부가기능), 포인트컷(선정 알고리즘)을 프록시로부터 분리 및 공유
    • 자동 프록시 생성 방법과 포인트컷
      • 프랜잭션 적용 대상 빈마다 일일이 프록시 팩토리 빈을 설정해야하는 문제
        • 스프링 컨테이너의 빈 생성 후처리 기법 적용
          • 컨테이너 초기화 시점에 자동으로 프록시 생성
          • 클래스 선정 포인트컷 사용
          • 포인트컷 표현식을 사용해서 간단한 설정만으로 적용 대상을 선정
    • 부가기능 모듈화
      • 트랜잭션 경계설정 기능이 다른 모듈의 코드에 부가적으로 부여되는 기능이어서 앞에서 학습해왔던 방법들로 간단하게 모듈화 불가
        • 다이내믹 프록시, IoC/DI 컨테이너 빈 생성 작업을 가로채서 빈 오브젝트를 프록시로 대체하는 빈 후처리 기술, 데코레이터 패턴, 자동 프록시 생성, 포인트컷 등 복잡한 기술 요구
        • 위의 기술을 이용해서 TransactionAdvice라는 이름으로 모듈화
    • AOP: 애스펙트 지향 프로그래밍
      • 애스펙트(Aspect)
        • 자체로 애플리케이션 핵심 기능은 없지만, 구성하는 중요한 한 가지 요소로, 핵심기능에 부가되어 의미를 갖는 특별한 모듈
        • 어드바이스와 포인트컷을 함께 가지고 있음
          • 앞선 예시들의 어드바이저가 단순한 형태의 Aspect
        • 핵심기능 코드 사이에 침투한 부가기능을 독립적인 모듈인 애스펙트로 구분하여 사용
          • 핵심기능은 순수하게 그 기능만을 담당, 독립적으로 구분
          • 자신이 필요한 위치에 다이내믹하게 참여하지만, 설계 및 개발은 독립적인 관점으로 진행
      • 애스펙트 지향 프로그래밍(Aspect Oriented Programming, AOP)
        • 애플리케이션의 핵심적인 기능에서 부가기능을 분리해서 Aspect 모듈로 만들어서 설계 & 개발하는 방법
        • OOP를 돕는 보조 기술
        • 애플리케이션을 특정한 관점을 기준으로 바라볼 수 있게 해준다는 의미에서 AOP를 관점 지향 프로그래밍이라고도 부름

    6.5.5 AOP 적용기술

    • 프록시를 이용한 AOP
      • 프록시로 만들어 DI로 연결된 빈 사이에 적용해서 타깃 메소드 호출 과정에 참여하여 부가기능을 제공
        • 스프링 AOP는 자바의 기본 JDK와 스프링 컨테이너 외에 기술과 환경을 요구하지 않음
      • 스프링 AOP의 어드바이스(부가기능)가 적용되는 대상은 오브젝트의 메소드이며, 프록시 방식이기에 메소드 호출 과정에서 부가기능을 제공
        • InvocationHandler의 작동 방식과 마찬가지로 어드바이스가 구현하는 MethodInterceptor 인터페이스가, 프록시로부터 요청을 받아서 타깃 오브젝트의 메소드를 호출
    • 바이트코드 생성과 조작을 통한 AOP
      • 프록시 방식이 아닌 AOP
        • AOP 기술의 원조, 가장 강력한 AOP 프레임워크인 AspectJ
        • 다이내믹 프록시 방식이 아닌, 타깃 오브젝트를 뜯어고쳐서 부가기능을 직접 넣어주는 방법 사용
        • 컴파일된 타깃의 클래스 파일 자체를 수정하거나, JVM에 로딩되는 시점에 가로채서 바이트 코드를 조작
      • 프록시를 사용하지 않는 이유
        • 바이트코드를 조작해서 타깃 오브젝트를 직접 수정하면, 스프링과 같은 DI 컨테이너의 도움을 받지 않아도 AOP를 적용할 수 있기 때문
          • 컨테이너가 사용되지 않는 환경에서도 AOP를 손쉽게 적용 가능
        • 프록시 방식보다 강력하고 유연한 AOP 가능
          • 프록시를 사용하면, 부가기능 추가는 클라이언트가 호출할 때 사용하는 메소드로 한정
          • 직접 바이트코드를 조작하면 오브젝트의 생성, 필드 값의 조회 & 조작, 스태틱 초기화 등 다양한 부가기능 부여 가능
      • 고급 AOP 기술은 바이트코드 조작을 위해 JVM의 실행 옵션을 변경하거나, 별도의 바이트코드 컴파일러를 사용하거나, 특별한 클래스 로더를 사용하는 등 번거로움
        • 일반적인 AOP를 적용할 때는, 프록시 방식의 스프링 AOP로 충분

    6.5.6 AOP의 용어

    • 타깃
      • 부가기능을 부여할 대상
      • 핵심 기능을 담은 클래스 or 다른 부가기능을 제공하는 프록시 오브젝트
    • 어드바이스
      • 타깃에 제공할 부가기능을 담은 모듈
      • 오브젝트로 정의하거나 메소드 레벨에서 정의해서 사용
      • MethodInterceptor처럼 메소드 호출 과정에 전반적으로 참여하는 것, 예외 발생 시에만 동작하는 등의 메소드 호출 과정의 일부만 동작하는 등 여러 종류가 존재
    • 조인 포인트
      • 어드바이스가 적용될 수 있는 위치
      • 스프링 프록시 AOP에서 메소드의 실행 단계
      • 타깃 오브젝트가 구현한 인터페이스의 모든 메소드
    • 포인트컷
      • 어드바이스를 적용할 조인 포인트를 선별하는 작업 or 기능을 정의한 모듈
      • 스프링 AOP의 조인 포인트는 메소드 실행 ~> 스프링의 포인트컷은 메소드 선정 기능
      • excution으로 시작하고, 메소드 시그니처를 비교하는 방법을 주로 이용
    • 프록시
      • 클라이언트와 타깃 사이에 존재하며 부가기능을 제공하는 오브젝트
      • DI를 통해 타깃 대신 클라이언트에게 주입, 클라이언트의 메소드 호출을 대신 받아 타깃에 위임하면서 부가기능을 부여
      • 스프링은 프록시를 통해 AOP 지원
    • 어드바이저
      • 포인트컷 + 어드바이스 쌍의 오브젝트
      • 어떤 부가기능(어드바이스)을 어디에(포인트컷) 전달할 것인지 알고있는 AOP의 가장 기본이 되는 모듈
      • 스프링 AOP에서만 사용되는 용어
        • 일반 AOP에서는 사용 X
    • 에스펙트
      • AOP의 기본 모듈
      • 한 개 이상의 포인트컷과 어드바이스 조합으로 만들어지며, 보통 싱글톤 형태의 오브젝트
      • 스프링의 어드바이저는 아주 단순한 Aspect

    AOP 네임스페이스

    • 스프링 AOP를 적용하기 위해 추가한 어드바이저, 포인트컷, 자동 프록시 생성기 같은 빈들은 애플리케이션 로직을 담은 빈과 달리, 스프링 컨테이너에 의해 자동으로 인식돼서 특별한 작업을 위해 사용됨
    • 스프링의 프록시 방식을 AOP에 적용하기 위한 빈 등록
      • 자동 프록시 생성기
        • 스프링의 DefaultAdvisorAutoProxyCreator 클래스를 빈으로 등록
        • 다른 빈을 DI하지 않고, 자신도 DI 되지 않으며 독립적으로 존재
        • Application Context가 빈 오브젝트를 생성하는 과정에 빈 후처리기로 참여
        • 빈으로 등록된 어드바이저를 이용해 프록시를 자동으로 생성
      • 어드바이스
        • 부가기능을 구현한 클래스를 빈으로 등록
        • TransactionAdvice는 AOP 관련 빈 중 유일하게 직접 구현한 클래스를 사용
      • 포인트컷
        • 스프링의 AspectJExpressionPointcut을 빈으로 등록하고, expression 프로퍼티에 포인트컷 표현식을 넣어 사용
      • 어드바이저
        • 스프링의 DefaultPointcutAdvisor 클래스를 빈으로 등록해서 사용
        • 어드바이스와 포인트컷을 프로퍼티로 참조하고, 자동 프록시 생성기에 의해 자동 검색되어 사용됨
    • AOP 네임스페이스
      • 스프링은 AOP와 관련된 태그를 정의해둔 aop 스키마를 제공
        • 별도의 네임스페이스를 지정해서 디폴트 네임스페이스의 <bean> 태그와 구분해서 사용
        • 설정 파일에 springframwork의 aop를 등록해서 사용
        • <aop:config>, <aop:pointcut>, <aop:advisor> 세 태그를 정의하면 빈이 자동으로 등록
        • transactionAdvice를 제외한 AOP 관련 빈들은 의미를 잘 드러내는 독립적인 전용 태그를 사용하도록 권장
    • 어드바이저 내장 포인트컷
      • AspectJ 포인트컷 표현식을 활용하는 포인트컷은 expression 프로퍼티를 설정해서 사용
      • 포인트컷은 어드바이저에 참조돼야 사용됨
        • 독립적으로 태그를 분리하지 않고 어드바이저 태그와 결합해서 사용가능
        • 포인트컷을 내장하면 두 개의 빈이 등록됨
    반응형

    댓글

Designed by Tistory.