ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java Spring] AOP 개념 및 사용 방법(AspectJ, xml, annotation)
    Programming/Java 2022. 10. 30. 18:12
    반응형

    AOP (Aspect Oriented Programming), 관점 지향 프로그래밍

    어떤 로직을 기준으로 핵심적인 관점(비즈니스 로직), 부가적인 관점을 나누어 그 관점을 기준으로 모듈화

    - 요청(Request)에 대해 핵심 관심사항(Aspect)과 부가 관심사항으로 나눠 관점을 기준으로 프로그램을 구현하는 기법

    - OOP: 사용자의 관점에서 필요한 핵심적인 비즈니스 로직을 구현하는데 있어 객체(클래스)를 모듈화함으로써 반복되는 코드를 줄임
    - AOP: OOP의 개념에 더해, 어플리케이션 전체에 사용되는 부가기능(Aspect)들을 모듈화, 공통 기능(Corsscutting Concerns)관리를 더 효율적으로 가능하게 함 (개발, 운영 측면에서 OOP를 더욱 강력하게 만듦)

    - 어플리케이션에서 계속 반복 사용되는 코드(Croscutting Concerns)를 Aspect로 모듈화하고 비즈니스 로직에서 분리하여 재사용하는 것이 핵심

    1. 스프링 AOP 주요 개념

    - Aspect: 여러 클래스에 공통적으로 구현되는 관심사(Concern)를 모듈화한 것(주로 부가기능)

    - Advice: 어떤 일을 해야할지에 대한 것, 해야 할 일에 대한 정보를 가지고 있음(Around, Before, After 등 타입 존재)
    - Target: Aspect가 가지고 있는 Advice가 적용되는 대상(클래스, 메서드 등).
    - JointPoint: Advice가 적용될 위치, 끼어들 수 있는 지점(생성자 호출 전, 생성자 호출 시, 메소드 실행 시 등)
    - PointCut: JointPoint의 상세한 스펙을 정의함으로써 구체적으로 Advice가 실행될 지점의 조건을 서술해놓은 것 

    - Weaving: Aspect를 대상 객체에 연결시켜 Advice 객체로 만드는 과정을 의미. 

    - AOP Proxy: AOP를 구현하기 위해 AOP 프레임워크에 의해 생성된 객체(JDK Proxy, CGLIB Proxy)

    2. Spring AOP Proxy

    - 비즈니스 로직이 구현된 Target 객체를 호출하면, Target이 아닌 Advice(부가 기능)가 적용된 Proxy 객체가 호출
    - Spring AOP는 기본값으로 표준 JDK dynamic proxy 사용
    - 인터페이스를 구현한 클래스가 아닌 경우 CGLIB proxy 사용
    - Spring AOP는 Spring 컨테이너가 관리하는 Bean에만 적용 가능

    3. AspectJ 통한 AOP 시작하기

    3-1. AspectJ 라이브러리(의존성) 추가

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
    	<groupId>org.aspectj</groupId>
    	<artifactId>aspectjweaver</artifactId>
    	<version>1.9.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
    <dependency>
    	<groupId>org.aspectj</groupId>
    	<artifactId>aspectjrt</artifactId>
    	<version>1.9.8</version>
    	<scope>runtime</scope>
    </dependency>

    3-2. xml 방식

    // 1. Aspect 선언하기
    
    // 핵심 관심사항이 정리된 클래스 (spring/aop/xml/MyAspect.java)
    public class MyAspect {
      public void before() {
        System.out.println("시험을 시작합니다.");
      }
      
      public void afterReturning() {
        System.out.println("시험을 종료합니다.");
      }
      
      public void afterThrowing() {
        System.out.println("부정행위로 퇴실처리 되었습니다.");
      }
      
      public void after() {
        System.out.println("퇴실합니다.");
      }
    }
    // 2. Aspect 클래스 bean 등록하기. (applicationContext.xml)
    // Aspect을 적용할 클래스 역시 bean등록해주기.
    <bean id="myAspect" class="spring.aop.xml" />
    <bean id="midtermExam" class="spring.aop.MidtermExam" />
    <!-- 3. PointCut 선언 (Spring AOP는 메서드 실행만 지원)
    (applicationContext.xml에서 선언) -->
    
    <aop:config> <!-- 어떤 aspect, pointCut이 적용될지 결정 -->
      <!-- 포인트컷 선언시 조인포인트에 대한 표현식과 포인트 컷 이름 포함 필요 -->
      <aop:pointcut expression="execution(public void spring.aop.*.doTest())" id="mypt" />
      <aop:aspect ref="myAspect">
        <!-- advice 타입에 따른 메서드 지정 -->
        <aop:before method="before" pointcut-ref="mypt" />
        <aop:after-returning method="afterReturning" pointcut-ref="mypt" />
        <aop:after-throwing method="afterThrowing" pointcut-ref="mypt" />
        <aop:after method="after" pointcut-ref="mypt" />
      </aop:aspect>
    </aop:config>

    3-3. Annotation 방식

    <!-- applicationContext.xml 설정 -->
    <!-- 1. @AspectJ 활성화 --->
    <aop:aspectj-autoproxy />
    
    <!-- 2. bean 등록을 위한 Component scan 설정 -->
    <context:component-scan base-package="spring.aop" />
    // 3. Bean 등록 및 Aspect설정
    
    @Component
    @Aspect
    public class MyAspect {
    
      @Pointcut("execution(public String spring.aop.*.doTest())")
      public void mypt(){
      }
      
      @Before("mypt()")
      public void before() {
        System.out.println("시험을 시작합니다.");
      }
      
      @AfterRetruning("mypt()")
      public void afterReturning() {
        System.out.println("시험을 종료합니다.");
      }
      
      @AfterThrowing("mypt()")
      public void afterThrowing() {
        System.out.println("부정행위로 퇴실처리 되었습니다.");
      }
      
      @After("mypt()")
      public void after() {
        System.out.println("퇴실합니다.");
      }
    }
    반응형

    댓글

Designed by Tistory.