Aspect Oriented Programming
AOP는 프로그램 구조에 대한 다른 방식의 생각을 제공함으로써 OOP를 보완한다.
- AOP는 문제를 바라보는 관점을 기준으로 프로그래밍하는 기법을 말한다.
- 문제를 해결하기 위한 핵심 관심 사항[1]과 전체에 적용되는 공통관심 사항[2]을 기준으로 프로그래밍함으로써 공통모듈을 여러 코드에 쉽게 적용할 수 있도록 도와준다.
- AOP에서 중요한 개념은 「횡단 관점의 분리(Separation of Cross- Cutting Concern)」이다.
- OOP를 더욱 OOP답게 만들어 준다.
OOP
OOP에서는 황단관점 분리를 위해 공통기능들을 하나의 클래스라는 단위로 모으고 그것들을 모듈로부터 분리함으로써 재사용성과 보수성을 높인다
각 모듈로부터 공통기능으로 분리하는 것으로 성공했지만 그 기능을 사용하기 위해 공통 기능을 호출하는 코드까지는 각 모듈로부터 분리할 수 없다. 그렇기 때문에 분리한 공통 기능을 이용하기 위한 코드가 각 모듈에 횡단으로 산재하게 된다.
AOP
AOP에서는 핵심 로직을 구현한 코드에서 공통 기능을 직접적으로 호출하지 않는다.
AOP에서는 분리한 공통 기능의 호출까지도 관점으로 다룬다. 그리고 이러한 각 모듈로 산재한 관점을 횡단 관점이라 부르고 있다.
AOP에서는 이러한 횡단 관점까지 분리함으로써 각 모듈로부터 관점에 관한 코드를 완전히 제거하는 것을 목표로 한다.
AOP에서는 핵심 로직을 구현한 코드를 컴파일 하거나, 컴파일된 클래스를 로딩하거나 또는 로딩한 클래스의 객체를 생성할때 핵심 로직 구현 코드 안에 공통기능이 삽입된다.
- Advice - Joinpoint에 삽입되어져 동작할 수 있는 코드.
- Joinpoint - 「클래스의 인스턴스 생성 시점」, 「메소드 호출 시점」및 「예외 발생 시점」과 같이 애플리케이션을 실행할 때 특정 작업이 시작되는 시점으로 Advice를 적용 가능한 지점.
- Pointcut - 여러 개의 Joinpoint를 하나로 결합한(묶은)것.
- Advisor - Advice와 Pointcut를 하나로 묶어 취급한 것.
- Weaving - Advice를 핵심 로직 코드에 삽입하는 것.
- Target - 핵심 로직을 구현하는 클래스.
- Aspect - 여러 객체에 공통으로 적용되는 공통 관점 사항.
스프링 API를 이용한 AOP
스프링에서 AOP를 구현하는 과정은 다음과 같다.
1. Advice 클래스를 작성한다.
2. 설정 파일에 Pointcut을 설정한다.
3. 설정 파일에 Advice와 Pointcut을 묶어 놓는 Advisor를 설정한다.
4. 설정 파일에 ProxyFactoryBean 클래스를 이용하여 대상 객체에 Advisor를 적용한다.
5. getBean( ) 메소드로 빈 객체(프록시 객체)를 가져와 사용한다.
Advice 작성
스프링 AOP는 메소드 호출 관련 Advice만 제공하며 이들 Advice는 인터페이스형태로 제공된다.
인터페이스 |
설명 |
MethodBeforeAdvice |
대상 객체의 메소드를 실행하기 전에 공통기능을 실행할때 사용되는 Advice |
AfterReturningAdvice |
대상 객체의 메소드 실행 이후에 공통기능을 실행할때 사용되는 Advice. |
ThrowsAdvice |
대상 객체의 메소드가 실행하는 도중 예외가 발생할 경우 공통기능을 실행할 때 사용되는 Advice. |
MethodInterceptor |
위 세가지를 하나로 묶은 Advice로 메소드 실행 전, 후, 예외 발생시 공통 기능을 실행할 수 있다. |
MethodInterceptorm로 구현하는 방법
PerformanceCheckAdvice.java
public class PerformanceCheckAdvice implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { String methodName = invocation.getMethod().getName(); long start = System.nanoTime(); System.out.println("[Log]Method Before --> " + methodName + "time check start"); Object o = null; try { //대상 객체의 메소드를 실행하기 전에 사용되는 코드 o = invocation.proceed(); //대상 객체의 메소드 실행 이후에 사용되는 코드 } catch (Exception e) { e.printStackTrace(); System.out.println("[Log]Method Error --> " + methodName ); } long end = System.nanoTime(); System.out.println("[Log]Method After --> " + methodName + "processing time is "+(end-start)+"ns"); return o; } } |
GreetingServiceImpl.java
public class GreetingServiceImpl implements GreetingService { private String greeting; public GreetingServiceImpl(String greeting) { this.greeting = greeting; } public void sayHello(String name) { System.out.println(greeting + "\t" + name); } } |
applicationContext.xml
<bean id="greetingTarget" class="myspring.aop.GreetingServiceImpl"> <constructor-arg> <value>Hello</value> </constructor-arg> </bean> <!-- 1. Advice 빈으로 등록 --> <bean id="performanceAdvice" class="myspring.aop.PerformanceCheckAdvice" /> <!-- 2. pointcut 빈으로 등록 --> <bean id="helloPointCut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut"> <property name="expression"> <value>execution(public void say*(..))</value> </property> </bean> <!-- 3. Advisor 설정 --> <bean id="helloAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice"> <ref bean="performanceAdvice" /> </property> <property name="pointcut"> <ref bean="helloPointCut" /> </property> </bean> <!-- 4. target객체에 위빙 --> <bean id="greeting" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref bean="greetingTarget" /> </property> <property name="interceptorNames"> <list> <value>helloAdvisor</value> </list> </property> </bean> |
참고자료
'개발자 센터 > Spring' 카테고리의 다른 글
Spring 참고 사이트 (0) | 2009.12.13 |
---|---|
Spring에서 iBatis 연동하기 (7) | 2009.12.13 |
빈 라이프 사이클 (0) | 2009.12.13 |
제어의 역행 / 의존성 주입(Inversion of Control / Dependency Injection) (0) | 2009.12.13 |
Spring Framework의 개요 (0) | 2009.12.13 |