본문 바로가기

좋아하는 것_매직IT/1.spring

AOP(Aspect-Oriented Programming) 깔끔하게 정리하기

반응형

 

AOP (Aspect-Oriented Programming)란, 객체 지향 프로그래밍에서 핵심 비즈니스 로직과 공통적으로 발생하는 부가적인 로직을 분리해서 구현하는 방법론 중 하나입니다.

AOP는 어플리케이션 전체에서 발생하는 문제들을 해결하기 위해 개발되었습니다.

기본적으로 AOP는 애플리케이션의 핵심 로직과 비즈니스 로직을 분리하여, 공통으로 사용되는 코드를 모듈화하고, 코드 재사용성을 높이기 위한 기술입니다. AOP를 사용하면 다음과 같은 이점이 있습니다.

728x90
  1. 코드 중복 최소화 : 로깅, 예외 처리, 트랜잭션 처리 등과 같은 공통된 기능을 여러 곳에서 중복적으로 구현할 필요 없이 한 곳에서 처리할 수 있습니다.
  2. 모듈화 : 각 모듈의 능을 분리하여 유지보수가 용이합니다.
  3. 유연성 : 핵심 로직에서는 건드리지 않고 부가적인 기능을 추가할 수 있습니다.
  4. 코드 가독성 : 핵심 로직과 부가적인 기능이 분리되어 있기 때문에 코드를 읽기 쉽고 유지보수하기 쉽습니다.

AOP를 구현하기 위해 Spring Framework에서는 AspectJ 라이브러리를 사용합니다. AspectJ는 AOP를 구현하기 위한 기능들을 제공합니다.

AspectJ를 이용해서 AOP를 구현하면, 다음과 같은 구성요소들이 필요합니다.

  1. Aspect : 어떤 부가적인 기능을 수행할지를 정의합니다. 로깅, 예외 처리, 트랜잭션 처리 등이 될 수 있습니다.
  2. Join point : Aspect가 적용될 지점을 의미합니다. 예를 들어, 메소드 호출이나 예외 발생 등이 될 수 있습니다.
  3. Pointcut : 어떤 Join point에서 Aspect를 적용할 것인지를 정의합니다. AspectJ에서는 Pointcut 표현식을 사용합니다.
  4. Advice : Join point에서 Aspect가 적용되었을 때 수행될 코드를 정의합니다. Before, After, Around 등의 Advice 타입이 있습니다.
  5. Weaving : Aspect를 적용하는 과정을 의미합니다. AspectJ는 컴파일 시점에 Weaving을 수행합니다.

AspectJ를 이용한 AOP는 XML 설정 파일을 통해 구현할 수도 있습니다. AspectJ는 Spring Framework의 다양한 모듈과 함께 사용할 수 있기 때문에, Spring Framework를 사용하는 개발자들에게는 유용한 기술입니다.

AOP에서는 Aspect라는 개념이 중요합니다. Aspect는 핵심 로직과 관련이 없는, 하지만 여러 모듈에서 공통적으로 사용되는 기능을 정의합니다. 예를 들어, 로깅, 보안, 트랜잭션 처리 등이 있습니다. 이러한 기능들은 핵심 로직에서 분리되어 정의됩니다.

AOP에서는 핵심 로직에서는 건드리지 않고, Aspect를 통해 부가적인 기능을 추가합니다. 이렇게 분리된 기능들은 모듈화되어 유지보수가 용이해집니다. 또한 코드의 중복이 최소화되어 코드 가독성이 높아집니다.

AOP에서는 Join point와 Pointcut이라는 개념도 중요합니다. Join point는 Aspect를 적용할 지점을 의미하며, 예를 들어 메소드 호출이나 예외 발생 등이 될 수 있습니다. Pointcut은 어떤 Join point에서 Aspect를 적용할 것인지를 정의합니다. AspectJ에서는 Pointcut 표현식을 사용하여 정의할 수 있습니다.

Advice는 Join point에서 Aspect가 적용되었을 때 수행될 코드를 정의합니다. Before, After, Around 등의 Advice 타입이 있습니다. Before Advice는 Join point 이전에 수행되고, After Advice는 Join point 이후에 수행됩니다. Around Advice는 Join point의 전후에 수행됩니다.

AOP에서는 Weaving이라는 개념도 중요합니다. Weaving은 Aspect를 적용하는 과정을 의미합니다. AspectJ는 컴파일 시점에 Weaving을 수행합니다. 이렇게 Aspect가 적용된 코드는 컴파일된 후에 실행됩니다.

Spring Framework에서는 AspectJ 라이브러리를 이용하여 AOP를 구현할 수 있습니다. AspectJ를 이용한 AOP는 XML 설정 파일을 통해 구현할 수도 있습니다. Spring Framework에서는 다양한 모듈과 함께 사용할 수 있기 때문에, Spring Framework를 사용하는 개발자들에게는 유용한 기술입니다.

AOP에서는 대상 객체를 대상으로 하나 이상의 Aspect를 적용할 수 있습니다. Aspect를 적용할 대상 객체를 Proxy 객체로 대체하는 방식을 이용하여 AOP를 구현할 수 있습니다. 이때 Proxy 객체는 대상 객체를 래핑하여 Aspect가 적용된 새로운 객체를 생성합니다.

Spring AOP에서는 JDK Dynamic Proxy와 CGLIB Proxy 두 가지 방식을 이용하여 Proxy 객체를 생성합니다. JDK Dynamic Proxy는 인터페이스를 구현한 클래스에 대해서만 Proxy 객체를 생성할 수 있습니다. CGLIB Proxy는 클래스의 하위 클래스를 생성하여 Proxy 객체를 생성합니다. 이때, 대상 객체가 final 클래스이거나 final 메서드를 갖는 경우에는 CGLIB Proxy를 이용하여 Proxy 객체를 생성할 수 없습니다.

Spring AOP에서는 어노테이션 기반 AOP를 지원합니다. @Aspect 어노테이션을 이용하여 Aspect 클래스를 정의하고, @Pointcut, @Before, @After, @Around 등의 어노테이션을 이용하여 Pointcut과 Advice를 정의할 수 있습니다.

Spring AOP에서는 XML 설정 파일을 이용하여 AOP를 구현할 수도 있습니다. aop:config 태그를 이용하여 Aspect, Pointcut, Advice를 정의할 수 있습니다. 이때, aop:advisor 태그를 이용하여 대상 객체와 Aspect를 연결할 수 있습니다.

AOP를 이용하여 비즈니스 로직과 관련 없는 부가적인 기능들을 분리하고 모듈화하여 유지보수성과 가독성을 높일 수 있습니다. Spring Framework에서는 다양한 모듈과 함께 사용할 수 있기 때문에, Spring Framework를 이용하는 개발자들에게 AOP는 유용한 기술 중 하나입니다.

AOP는 크게 두 가지로 나눌 수 있습니다. 첫 번째는 메소드 실행 시점에 Aspect를 적용하는 방법이고, 두 번째는 메소드를 호출하지 않고 객체의 프로퍼티나 필드에 접근할 때 Aspect를 적용하는 방법입니다. 이러한 방법을 이용하여 AOP를 구현할 수 있습니다.

Spring AOP에서는 다양한 Advice 타입을 지원합니다. Before, After, Around 등의 Advice 타입은 이미 언급했지만, AfterReturning, AfterThrowing 등의 Advice 타입도 있습니다. AfterReturning Advice는 Join point가 정상적으로 수행되었을 때 수행됩니다. AfterThrowing Advice는 Join point에서 예외가 발생했을 때 수행됩니다.

AOP에서는 Aspect가 여러 개일 경우, Aspect들의 우선순위를 지정할 수 있습니다. 이를 위해서는 @Order 어노테이션을 이용하여 Aspect의 순서를 지정해줄 수 있습니다.

Spring AOP에서는 Proxy 객체를 이용하여 AOP를 구현하는 방식을 이용하기 때문에, 대상 객체와 Proxy 객체는 다른 객체입니다. 이때, 대상 객체의 메서드를 호출할 때 Proxy 객체를 통해 호출하게 되므로, 대상 객체의 메서드 호출 시점에만 Aspect가 적용됩니다.

AOP를 이용하여 로깅, 보안, 트랜잭션 처리 등을 구현할 수 있습니다. 이러한 기능들은 대부분의 애플리케이션에서 공통적으로 필요한 기능들이므로, AOP를 이용하여 모듈화하면 애플리케이션의 유지보수성과 가독성을 높일 수 있습니다.

AOP는 Spring Framework에서 중요한 기술 중 하나이며, 스프링에서는 AOP를 이용하여 트랜잭션 처리, 보안, 캐싱, 로깅 등 다양한 기능을 제공합니다. Spring AOP를 이용하여 애플리케이션의 성능과 유지보수성을 향상시킬 수 있습니다.

예시코드를 통해서 한번 알아보면요..
예시 코드를 통해 AOP의 구현 방법을 이해해보겠습니다.

먼저, Spring AOP에서는 대상 객체를 Proxy 객체로 대체하여 AOP를 구현합니다. 이를 위해서는 대상 객체가 인터페이스를 구현한 클래스일 경우 JDK Dynamic Proxy를, 인터페이스를 구현하지 않은 클래스일 경우 CGLIB Proxy를 이용하여 Proxy 객체를 생성합니다. 예시 코드는 다음과 같습니다.

public interface UserService {
    void addUser(User user);
    User getUserById(int id);
}

public class UserServiceImpl implements UserService {
    @Override
    public void addUser(User user) {
        // 사용자 추가 로직
    }
    
    @Override
    public User getUserById(int id) {
        // 사용자 조회 로직
        return null;
    }
}

// Proxy 객체를 생성하기 위한 Factory 클래스
public class ProxyFactory {
    public static UserService createUserService() {
        UserService userService = new UserServiceImpl();
        // Proxy 객체 생성
        InvocationHandler handler = new UserServiceInvocationHandler(userService);
        return (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                handler);
    }
}

// InvocationHandler 클래스
public class UserServiceInvocationHandler implements InvocationHandler {
    private final UserService target;

    public UserServiceInvocationHandler(UserService target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Before Advice
        Object result = method.invoke(target, args);
        // After Advice
        return result;
    }
}

위 예시 코드에서는 UserService 인터페이스를 구현한 UserServiceImpl 클래스가 대상 객체입니다. ProxyFactory 클래스는 UserServiceImpl 객체를 생성한 후, UserServiceInvocationHandler 객체를 이용하여 Proxy 객체를 생성합니다. UserServiceInvocationHandler는 invoke 메서드를 오버라이딩하여 Before Advice와 After Advice를 적용합니다. Before Advice에서는 대상 객체의 메서드 호출 전에 수행할 로직을 작성하고, After Advice에서는 대상 객체의 메서드 호출 후에 수행할 로직을 작성합니다.

예를 들어, Before Advice에서는 로깅을 수행하고, After Advice에서는 트랜잭션 처리를 수행할 수 있습니다. 이를 위해서는 Advice 타입을 지정하여 각 Advice에서 수행할 로직을 구현하면 됩니다.

// Before Advice
public class LoggingAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("Method " + method.getName() + " is called.");
    }
}

// After Advice
public class TransactionAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        // 트랜잭션 처리
    }
}

// Around Advice
public class TimeLoggingAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = invocation.proceed();
        long endTime = System.currentTimeMillis();
        System.out.println("Method " + invocation.getMethod().getName() + " took " + (endTime - startTime) + "ms.");
        return result;
    }
}

// After Throwing Advice
public class ExceptionLoggingAdvice implements ThrowsAdvice {
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
        System.out.println("Exception occurred in method " + method.getName() + ": " + ex.getMessage());
    }
}

// After Returning Advice
public class ResultLoggingAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("Method " + method.getName() + " returned: " + returnValue);
    }
}

Spring AOP에서는 Before Advice, After Advice, Around Advice, After Throwing Advice, After Returning Advice 등 다양한 Advice를 제공합니다. 이를 이용하여 로깅, 트랜잭션 처리, 보안 처리 등을 수행할 수 있습니다.

오늘의 블로그는 여기까지고요..
항상 믿고 봐주셔서 감사합니다. 
300x250