Spring - AOP

흑이·2022년 7월 7일
0

AOP(Aspect Oriented Programming)

AOP를 한글로 번역하면 관심 지향 프로그래밍으로 해석할 수 있다.

관심(Aspect)을 지향하는 프로그래밍에서 관심은 무엇을 의미?

애플리케이션에 필요한 기능 중에서 공통적으로 적용되는 공통 기능에 대한 관심과 관련이 있다.


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

애플리케이션 전반에 걸쳐 공통적으로 사용되는 기능들에 대한 관심사를 공통 관심 사항(Cross-cutting concern)이라고 한다.

비즈니스 로직, 애플리케이션의 주 목적을 달성하기 위한 핵심 로직에 대한 관심사를 핵심 관심 사항(Core concern)이라고 한다.

커피 주문을 위한 애플리케이션을 예

고객에게 제공하는 커피 메뉴를 구성하기 위해 커피 종류를 등록하는 것과 고객이 마시고 싶은 커피를 주문하는 기능은 애플리케이션의 핵심 관심 사항

하지만 커피 주문 애플리케이션에 아무나 접속하지 못하도록 제한하는 애플리케이션 보안에 대한 부분은 애플리케이션 전반에 공통적으로 적용되는 기능이기 때문에 공통 관심 사항

AOP라는 것은 애플리케이션의 핵심 업무 로직에서 로깅이나 보안, 트랜잭션 같은 공통 기능 로직들을 분리하는 것



AOP가 필요한 이유

애플리케이션의 핵심 로직에서 공통 기능을 분리하는 이유가 무엇일까?

  • 코드의 간결성 유지
  • 객체 지향 설계 원칙에 맞는 코드 구현
  • 코드의 재사용

애플리케이션 핵심 로직에 공통적인 기능의 코드들이 여기 저기 보이면 코드가 복잡해 짐

코드 구성이 복잡해지면 유지보수가 어려워 지는 코드가 됨


AOP가 적용되지 않는 JDBC 트랜잭션 예

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();
    }
}

트랜잭션(Transaction)이란 ‘데이터를 처리하는 하나의 작업 단위’를 의미
예를 들어 데이터베이스에 A 데이터와 B 데이터를 두 번에 걸쳐 각각 insert 하는 작업을 하나의 트랜잭션으로 묶는다면 A 데이터와 B 데이터는 모두 데이터베이스에 저장되던가 아니면
둘 중에 하나라도 오류로 인해 저장되지 않는다면 A, B 데이터는 모두 데이터베이스에 반영되지 않아야 한다.(All or Nothing).

(1)의 connection.setAutoCommit(false)이나
(3)의 connection.commit()
(4)의 connection.rollback()은
saveMember()와 savePoint() 작업을 트랜잭션으로 묶어서 처리하기 위한 기능들

이렇게 트랜잭션 처리를 하는 코드들이 애플리케이션의 다른 기능에도 중복되어 나타날 것

중복된 코드를 공통화해서 재사용 가능하도록 만들어야 한다. 그리고 이 공통화 작업은 AOP를 통해서 할 수 있다.

Spring에서는 이미 이런 트랜잭션 처리 기능을 AOP를 통해서 공통화 처리


Spring AOP 기능이 적용된 JDBC 트랜잭션 예

@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를 이용한 포인트 정보 저장
    }
}

트랜잭션 처리를 위한 코드들이 모두 사라지고 순수하게 비즈니스 로직을 처리하기 위한 saveMember(member)와 savePoint(point)만 남은 것을 볼 수 있다.

트랜잭션 처리는 어떻게??

(1)의 @Transactional 애노테이션 하나만 붙이면 Spring 내부에서 이 애노테이션 정보를 활용해서 AOP 기능을 통해 트랜잭션을 적용한다.

이처럼 AOP를 활용하면 애플리케이션에 전반에 걸쳐 적용되는 공통 기능(트랜잭션, 로깅, 보안, 트레이싱, 모니터링) 등을 비즈니스 로직에서 깔끔하게 분리하여 재사용 가능한 모듈로 사용할 수 있다.

0개의 댓글