AOP (관점지향형프로그래밍)

AOP


AOP (Aspect-Oriented-Programing) - 관점지향형프로그래밍

객체지향프로그래밍(OOP)은 많은 장점들을 가지고 있다.

코드를 작성하다 보면 중복되는 method나 field가 존재한다.
이러한 코드를 재사용성과 사용에 더 용이하게 하기 위해 bean class로 만든다.

하지만 bean class와 그 안에 구현되있는 method나 field는 bean class에 의존성을 가지게된다.

이러한 의존관계를 디커플링 관계로 만들어 주는 것, 제3자의 관점에서 본다는 개념, 핵심기능과 부가기능을 분리된 모듈로써 나눠주는 것을 AOP라 한다.

AOP 용어정리


타겟(Target) - Core Concerns(핵심기능)

  • 핵심 기능을 담고 있는 모듈로, 타겟은 부가 기능을 부여할 대상이다. getBoards 혹은 getUsers를 하는 Service 들을 얘기합니다.
  • 구현된 method와 field를 가지는 Bean Class이다.

어드바이스(Advice) - Cross-cutting-Concerns(부가기능)

  • 어드바이스는 타겟에 제공할 부가기능을 담고 있는 모듈이다.
  • Bean Class안에 구현되어 사용되는 method나 field

조인 포인트(JointPoint)

  • 어드바이스가 적용될 수 있는 위치를 말함
  • 즉, 타겟 객체가 구현한 인터페이스의 모든 메서드는 조인 포인트가 된다.
  • Adivce를 적용해야 되는 부분(EX: 필드, 메소드/ 스프링에서는 메소드)

포인트컷(PointCut)

  • 어드바이스를 적용할 타겟의 메서드를 선별하는 정규표현식
  • 포인트컷 표현식은 execution으로 시작하고, 메서드의 Signature를 비교하는 방법을 주로 이용
  • Joinpoint의 부분으로 실제로 Advice가 적용된 부분 -PointCut은

애스펙트(Aspect) - 일반적인 명칭

  • 애스펙트는 AOP의 기본 모듈
  • 애스펙트 = 어드바이스 + 포인트컷
  • 애스펙트는 싱글턴 형태의 객체로 존재.

어드바이저(Advisior)

  • 어드바이저 = 어드바이스 + 포인트컷
  • 어드바이저는 Spring AOP에서만 사용되는 특별한 용어.
  • 어드바이저와 에스펙트는 같은 개념을 갖는다.

위빙(Weaving)

  • 위빙은 포인트컷에 의해서 결정된 타겟의 조인 포인트에 부가기능 (어드바이스)을 삽입하는 과정을 뜻한다.
  • 위빙은 AOP가 핵심기능(타겟)의 코드에 영향을 주지 않으면서 필요한 부가기능(어드바이스)을 추가할 수 있도록 해주는 식심적인 처리과정
  • 위빙은 Target와 Aspect를 합치는 과정이다. (Proxy)
  • Target과 Advice를 연결하는 class(?)

프록시(Proxy)

  • 개발을 분리하여 진행하면 그것을 연결하는 매개체
  • Proxy : 내가 만든 것
  • Dynamic-Proxy : 프레임워크에서 제공하는 것

AOP Spring 적용


AOP개념은 스프링에서 적용이 가능하며 스프링에서도 AOP를 지원하는 프레임워크를 제공해준다.

다른 프레임워크도 AOP를 지원하지만 스프링을 Bean/IoC를 지원하여 많은 선택을 받고 있다.

Spring에서 사용하는 방법은 2가지로 .xml과 @어노테이션을 이용하는 방법이 있다.

.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans 	xmlns="http://www.springframework.org/schema/beans"
				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">

<!-- 생성 -->							  
<bean id="message" class="spring.service.aop.impl.MessageImpl"/>
<!-- 생성 -->
<bean id="testAdvice" class="spring.service.aop.advice.TestAdvice"/>

<!-- Pointcut -->
<!--  <bean id="testPointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
	<property name="expression" value="execution(public !void get*(..))"/>
</bean> 
 -->

<!-- 예외처리 -->
<bean id="testAdvisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
	<property name="advice" ref="testAdvice"/>
	<property name="expression" value="execution(* *.getMessage(..))"/>
	<!-- <property name="pointcut" ref="testPointcut"/>  -->
</bean>

<!-- AutoProxy (weaving) -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>


<!-- Proxy (weaving) -->
<!-- <bean id="message" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces" value="spring.service.aop.Message"/>  #Target이 인터페이스를 구현하기에 생략가능
	<property name="interceptorNames" value="testAdvisor"/>
	<property name="target" ref="messageTarget"/>
</bean>
 -->
</beans>

Target


public class MessageTestAppUseSpringAOP02 {
	
	///Main Method
	public static void main(String[] args) throws Exception{

		ApplicationContext context = 
		
				new ClassPathXmlApplicationContext("/config/messageservice.xml");
		
		//==> IoC Container 로 부터 Look Up 한 인스턴스는 ProxyFactoryBean 객체가 생성해준 
		//==> Message interface 구현한 Dynamic Proxy
		Message message = (Message)context.getBean("message");

		//==> 실행방법
		//::1. 인자 : String 전달
	    message.setMessage("Hello");
	    //::2. 인자 : null 전달 : ThrowsAdvice 동작확인
		//message.setMessage(null);
	    
	    System.out.println("\n\n+++++++++++++++++++++++++++++++++++++++++++++\n\n");
		
	    System.out.println("\n리턴 받은 메세지 : "+message.getMessage());
	}
}//end of class

Aspect(Advice + pointcut)


public class TestAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice, MethodInterceptor {

	public void before(Method method, Object[] args, Object target) throws Throwable {
		
		System.out.println("[before Log]" +getClass()+".before() start....");
		System.out.println("[before Log] targetObject call Method : " +method);
		if( args.length != 0) {
			System.out.println("[before Log]targetObject Method 전달 agument : "+args[0]);
		}
		System.out.println("[before Log]" +getClass()+".before() end....");
	}
	
	public void afterReturning ( Object returnValue, Method method, Object[] args, Object target) throws Throwable{
		System.out.println("[after LOG] "+getClass()+".afterReturning() start....");
		System.out.println("[after LOG] targetObject call Method : "+method);
		System.out.println("[after LOG] 타겟 객체의 호출후 return value : "+returnValue);
		System.out.println("[after LOG] "+getClass()+".afterReturning() end....");
	}
	
	public  Object invoke(MethodInvocation invocation) throws Throwable{
		System.out.println("[Around before] "+getClass()+".invoke() start.....");
		System.out.println("[Around before] targetObject call Method : "+invocation.getMethod());
		if(invocation.getArguments().length != 0) {
			System.out.println("[Around before] targetObject method 전달 argument : "
											+ invocation.getArguments()[0]);
		}
		
		Object obj = invocation.proceed();
		
		System.out.println("[Around after] 타겟 객체의 호출후 return value : "+obj);
		System.out.println("[Around after] "+getClass()+".invoke() end.....");
		return obj;
	}
	
	public void afterThrowing(Throwable throwable) {
		
		System.out.println("[exception] "+getClass()+".afterThrowing() start.....");
		System.out.println("[exception] Exception발생");
		System.out.println("[exception] Exception Message : "+throwable.getMessage());
		System.out.println("[exception] "+getClass()+".afterThrowing() end.....");
	}
	
}

Categories:

Updated:

Leave a comment