-
스프링4.0 - AOP 기초웹프로그래밍/spring 2018. 7. 15. 19:23
AOP란?
어플리케이션의 공통 관심 사항과 핵심 관심 사항을 기준으로 프로그래밍 하므로써 공통 모듈을 여러 코드에 쉽게 적용하는 것
핵심 로직에서 공통 기능을 직접 호출 하지는 않는다.
공통 기능은 컴파일하거나 클래스를 로딩할때, 또는 클래스의 객체를 생성할때 AOP가 적용된다.
즉, 핵심 로직 구현 코드에 공통 기능이 삽입된다.
※spring API 문서:
https://docs.spring.io/spring-framework/docs/2.0.x/reference/aop.html
AOP 용어
Joinpoint - 실행지점, 즉 Advice가 적용될 메소드
Pointcut - JoinPoint와 Advice를 연결해주는 설명어. 예를들어, Pointcut이 가리키는 특정 이름의 메소드에 Advice가 적용된다.
Advice - 공통 관심 기능을 JoinPoint에서 언제 적용할 것인지를 정의한다. ex) around, before, after Advice 등..
Weaving - 핵심로직과 Aspect를 연결하는 것. Spring AOP에서는 runtime 단계에서 수행된다.
Aspect - 공통 관심 모듈(ex. 트랜잭션 관리, 보안)
- 3가지 Weaving 방식
컴파일 시에 weaving - 자바 코드를 컴파일 하는 단계에서 핵심 로직이 구현된 자바 코드에 공통 코드를 삽입하면 AOP가 적용된 클래스 파일이 생성된다.
클래스 로딩 시에 weaving - JVM이 로딩한 클래스의 바이너리 정보를 토대로 알맞은 위치에 공통 코드를 삽입한 새로운 클래스 바이너리 코드를 만든다.
런타임 시에 weaving - 소스 코드나 클래스 정보를 직접 변경하지 않고 프록시를 이용하여 AOP를 적용한다. 오직 핵심 로직의 메소드가 실행되기 전이나 후에 프록시 객체를 이용하여 Advice를 적용한다. (필드 값 변경과 같은 Joinpoint는 적용할 수 없다.)
- Advice 종류
Before Advice - 대상 객체의 메서드 호출 전
After Returning Advice - 대상 객체의 메서드가 익셉션 업이 실행 된 이후
After Throwing Advice - 대상 객체의 메서드 실행 도중 익셉션이 발생한 경우
After Advice - 익셉션 여부에 관계없이 대상 객체의 메서드 실행 후
Around Advice - 대상 객체의 메서드 실행 전, 후
스프링에서의 AOP
스프링은 프록시 기반의 AOP를 지원한다. 오직 메소드 호출 Joinpoint만 지원하며 자바 언어 기반이다.
필드 값 변경과 같은 다양한 Joinpoint를 사용하려면 AspectJ를 사용해야 한다.
- 프록시를 이용한 AOP
스프링 컨테이너를 초기화하는 과정에서 xml 설정 정보에 저장된 bean 객체에 대한 프록시 객체를 생성해서
원본 bean 객체 대신 프록시 객체를 사용한다. 그 방식은 2가지로 나뉜다.
대상 객체가 인터페이스를 구현한 경우 - java.lang.reflect.Proxy를 이용하여 프록시 객체를 생성한다. 이때 생성된 프록시 객체는 대상 객체와 동일한
인터페이스를 구현하므로 인터페이스의 정의되지 않은 메서드에 대해서는 AOP가 적용되지 않는다.
대상 객체가 인터페이스를 구현하지 않은 경우 - 스프링이 CGLIB를 이용하여 대상 객체에 대한 프록시 객체를 생성한다. 즉, CGLIB가 대상 클래스를 상속받아 프록시를 구현한다. 그러므로 대상 클래스 또는 그 메서드가 final 인 경우 AOP를 적용할 수 없다.
- XML 스키마 기반 AOP 구현
1. pom.xml에 스프링 AOP를 사용하기 위한 의존 설정 추가
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
</dependencies>
2. 공통 기능을 제공할 클래스 구현
먼저, 클래스에서 org.aspectj.lang.ProceedingJoinPoint 클래스를 import한다.
그리고 Object 타입을 리턴하고 ProcedingJoinPoint 타입을 파라미터로 갖는 public 메소드를 만든다.
ProcedingJoinPoint 타입의 joinPoint 파라미터에 의해서 메소드를 공통 기능으로 구현할 수 있다.
import org.aspectj.lang.ProceedingJoinPoint;
public class Profiler {
public Object trace(ProceedingJoinPoint joinPoint) throws Throwable {
String signatureString = joinPoint.getSignature().toShortString();
System.out.println(signatureString + "시작");
long start = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
return result;
} finally {
long finish = System.currentTimeMillis();
System.out.println(signatureString + "종료");
System.out.println(signatureString + "실행 시간:"+(finish - start)+"ms");
}
}
}
3. XML 설정 파일에서 <aop:config>로 Aspect 설정 후 Advice가 적용될 Pointcut을 정한다.
<aop:pointcut>에서 expression은 spring.chap06 패키지 및 하위패키지에 모든 public 메서드를 Pointcut으로 설정한다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 공통 기능 제공 클래스 등록 -->
<bean id="profiler" class="spring.chap06.aop.Profiler"/>
<!-- Aspect 설정:Advice를 어떤 Pointcut에 적용할지 설정 -->
<aop:config>
<aop:aspect id="traceAspect" ref="profiler">
<aop:pointcut id="publicMethod"
expression="execution(public * spring.chap06..*(..))"/>
<aop:around method="trace" pointcut-ref="publicMethod"/>
</aop:aspect>
</aop:config>
<!-- 핵심 기능 제공 클래스 -->
<bean id="writeArticleService" class="spring.chap06.board.WriteArticleServiceImpl">
<constructor-arg>
<ref bean="articleDao" />
</constructor-arg>
</bean>
<bean id="articleDao" class="spring.chap06.board.MemoryArticleDao"/>
<bean id="memberService" class="spring.chap06.member.MemberServiceImpl"/>
</beans>
'웹프로그래밍 > spring' 카테고리의 다른 글
스프링4.0 - Validator / Errors / BindingResult로 객체 검증 : 에러 메시지 (0) 2018.07.17 스프링4.0 - AOP : @Aspect 기반 (0) 2018.07.16 스프링 4.0 - DI : 의존성주입 자동 연결 (0) 2018.07.10 스프링 4.0 - DI(Dependency Injection) : 의존성 주입 - 수동 설정 (0) 2018.07.10 스프링3.0 - Database 연동하기 (0) 2018.07.03