AOP ( Aspect Oriented Programming )

AOP 는 애플리케이션의 핵심 업무 로직에서 [ 로깅, 보안, 트랜잭션 ] 과 같은 공통 기능 로직들을 분리하는 것입니다.

 

공통 관심 사항, 핵심 관심 사항

애플리케이션의 주 목적을 달성하기 위한 핵심 로직에 대한 관심사는 핵심 관심 사항이라고 합니다.

이를 우리는 흔히 비지니스 로직이라고 부릅니다.

 

  • 핵심 관심 사항

1) 주인이 고객에게 제공하는 커피 메뉴를 구성하기 위해 커피 종류를 등록하는 기능

2) 고객이 마시고 싶은 커피를 주문하는 기능

 

  • 공통 관심 사항

1) 커피 주문 애플리케이션에 아무나 접속하지 못하도록 제한하는 보안적인 부분

2) 주문에 대한 모든 것을 기록하는 부분

3) 등록, 선택 등의 명령을 내리는 부분

 

위의 그림은 이 두가지 관심 사항을 나타낸 것입니다.

 

이렇게 핵심 업무 로직과 공통 업무 로직들을 분리하는 것을 AOP 라고 부릅니다.

 

그렇다면 이런 AOP 가 왜 필요한 것일까요 ??

 

 

AOP 가 필요한 이유

1) 코드의 간결성 유지

 

2) 객체 지향 설계원칙에 맞는 코드 구현

 

3) 코드의 재사용

 

위의 세가지 덕분에 유지보수를 보다 쉽게 할 수 있습니다.

 

 

Aspect ( 관심 )

AOP 는 애스펙트를 사용하여 다양한 기능을 분리합니다.

애스펙트는 부가 기능과 해당 부가 기능을 어디에 적용할지 정의한 것입니다.

또는 애스펙트는 관점이라는 뜻을 의미하여, 애플리케이션을 바라보는 관점을 하나 하나의 기능 -> 횡단 관심사 관점으로 보는 것입니다.

 

그래서 AOP 는 기존에 사용하던 OOP 를 대체하기 위한 것이 아닌 횡단 관심사를 깔끔하게 처리하기 위해 OOP 의 부족한 부분을

보조하는 목적으로 개발되었습니다.

 

  • 여러 객체에 공통으로 적용되는 기능
  • 애플리케이션에 포함되는 횡단 기능

 

* 용어 정리

 

 1) Advice : 부가기능을 정의한 코드 ( 조인 포인트에서 수행되는 코드 )

                 - 기본적으로 순서를 보장하지 않음 ( 보장하고 싶다면 @Order 필요 )

Advice 종류
1) Before
 - 조인 포인트 이전에 실행됨
 - 타겟 메서드가 실행되기 전에 처리해야할 필요가 있는 부가 기능을 호출 전에 공통 기능을 실행
 - 리턴타입이 void
 - 예외 발생시 메서드가 호출되지 않음

2) After returning
 - 조인 포인트가 정상 완료 후 실행됨

3) After throwing
 - 메서드가 예외를 던지는 경우 실행됨
 - 예외가 발생한 경우 공통 기능 실행

4) After
 - 조인 포인트 동작과는 상관없이 실행됨 ( 예외 동작의 finally 와 같음 )
 - 메서드 실행 후 공통 기능 실행
 - 일반적으로 메서드 해제하는데에 사용됨

5) Around
 - 메서드 호출 전후에 수행하며 가장 강력한 어드바이스
 - 어라운드만 있어도 모든 기능 수행 가능

 2) PointCut : Advice를 어디에 적용할지 결정하는 것

 

포인트컷 지시자 종류

 

 

 3) join point : 클래스 초기화, 메소드 호출, 예외 발생, 객체 인스턴스화 등과 같은 애플리케이션 실행 흐름에서의 특정 포인트

                         즉, AOP 적용 위치를 의미합니다.

단, 스프링 AOP 는 프록시 방식을 사용하므로 조인 포인트는 항상 메서드 실행 지점으로 제한됩니다.

 

 4) 위빙 : 포인트컷으로 결정한타겟의 조인 포인트에 어드바이스를 적용하는 것 ( 어드바이스를 핵심 코드에 적용하는 것 )

 5) AOP 프록시 : AOP 기능을 구현하기 위해 만든 프록시 객체

 6) 타겟 : 핵심 기능을 담고 있는 모듈로 타겟은 부가기능을 부여할 대상이 됨

 7) 어드바이저 : 하나의 어드바이스와 하나의 포인트 컷으로 구성 ( 스프링 AOP 에서만 사용되는 용어 )

 

 

OOP

  • 공통된 목적을 띈 데이터와 동작을 묶어 하나의 객체로 정의하는 것
  • 객체를 활용함으로써 기능을 재사용할 수 있음
  • 객체를 잘 활용하기 위해선 관심사 분리 (SoC) 디자인 원칙을 준수해야함

 

 

기능 분리

AOP 에서의 관심사 분리는 핵심 기능 , 부가 기능 으로 분리됩니다.

이러한 기능을 나누는데에 AOP 를 사용하는 이유는 다음과 같습니다.


  1.  부가기능이 불특정 다수의 여러곳에 작성되야 하는 경우를 방지
  2. 부가기능 수정시 사용된 모든 클래스에 수정하지 않게 하나로 관리할 수 있게 해줌

 

Spring MVC 구조는 @Controller, @Service, @Repository 와 같이 관심사 별로 계층을 나눠 객체를 관리합니다.

이러한 관심사의 분리는 모듈화의 핵심입니다.

 

  • 핵심 기능

- 객체가 제공하는 고유의 기능

 

  • 부가 기능

- 핵심 기능을 보조하기 위해 제공하는 기능

- 로그 추적, 보안, 트랜잭션 등의 기능

- 단독으로 사용하지 않고 핵심 기능과 함께 사용됨

 

 

 

소스 코드
public class Example2_11 {
    private Connection connection;

    public void registerMember(Member member, Point point) throws SQLException {
        connection.setAutoCommit(false); // (1)
        try {
            saveMember(member); // (2)
            savePoint(point);   // (2)
            
            connection.commit(); // (3)
        } catch (SQLException e) {
            connection.rollback(); // (4)
        }
    }

    private void saveMember(Member member) throws SQLException {
        PreparedStatement psMember =
                connection.prepareStatement("INSERT INTO member (email, password) VALUES (?, ?)");
        psMember.setString(1, member.getEmail());
        psMember.setString(2, member.getPassword());
        psMember.executeUpdate();
    }

    private void savePoint(Point point) throws SQLException {
        PreparedStatement psPoint =
                connection.prepareStatement("INSERT INTO point (email, point) VALUES (?, ?)");
        psPoint.setString(1, point.getEmail());
        psPoint.setInt(2, point.getPoint());
        psPoint.executeUpdate();
    }
}

위의 코드에서 아래의 기능들이 보여집니다.

  • member.save() 부분의 서비스 작업
  • em.persist(), tx.commit(), em.close() 와 같은 트랜잭션 작업

이렇게 AOP 없이 구현하게 되면 애플리케이션 전반적으로 트랜잭션과 관련된 중복된 코드가 수도 없이 나오게 됩니다.

 

스프링에서는 @Transactional 이라는 어노테이션을 통해서 AOP 기능을 적용할 수 있습니다.

 

@Component
@Transactional // (1)
public class Example2_12 {
    private Connection connection;

    public void registerMember(Member member, Point point) throws SQLException {
        saveMember(member);
        savePoint(point);
    }

    private void saveMember(Member member) throws SQLException {
        // Spring JDBC를 이용한 회원 정보 저장
    }

    private void savePoint(Point point) throws SQLException {
        // Spring JDBC를 이용한 포인트 정보 저장
    }
}

 

 

@Transactional

해당 클래스에 트랜잭션 기능이 적용된 프록시 객체가 생성됩니다.

프록시 객체는 @Transactional 이 포함된 메소드가 호출될 경우, 트랜잭션을 시작하고 정상 여부에 따라 커밋 또는 롤백됩니다.

 

* 단, 테스트 코드에서의 @Transactional 은 다른 기능을 하므로 주의해야합니다.

'스터디' 카테고리의 다른 글

스프링 컨테이너  (0) 2022.08.11
UML 작성법  (0) 2022.08.10
IoC / DI  (0) 2022.08.09
프레임워크와 라이브러리  (0) 2022.08.09
스키마와 쿼리 디자인  (0) 2022.08.04

+ Recent posts