[개념]_AOP [Aspect-Oriented Programming]

728x90

[AOP 목표]

- 기존 코드 수정 없이 원하는 관심사들을 엮어서 전체 구현 쉽게 하기

   즉, 개발자들이 핵심 로직 코드만 개발하고  나머지 코드 부분은 어떤 관심사들과 결합할지 설정 만으로                                  전체 기능 효율적 개발 추구

[AOP 개념]

- AOP : 핵심 기능/주변 기능 분리하여 코드 작성해놓고, 실행 시점에 결합하는 방식

핵심로직과 주변로직의 분리를 추구 = 관심사의 분리

핵심 비즈니스 로직과 부가기능(=공통기능) 코드의 분리 추구

          ex. 입력 값에 대한 나눗셈 기능 구현 시,
1) 입력 값이 0 이상의 양수인지 확인한는 기능 : 관심사(주변 로직)
2) 실질적인 입력값 간의 나눗셈 기능 : 비즈니스 로직(핵심 기능)

[AOP 용어들]

핵심 로직 관련

Target 객체 : 주요 핵심 로직 객체 자체. 순수한 Core

JointPoint : Target 객체가 가진 여러 메소드들.

주변 로직(관심사) 관련

Aspect (추상) : 관심사의 추상화 객체

Advice (구현) : Aspect를 구현한 실질적인 관심사 객체

엮는 애들

Pointcut : 핵심로직과 관심사 엮는 설정
            : Target의 어떤 JointPoint 지점에서 Advice를 엮을지 설정하는 부분

        1) XML 이용한 설정
        2) @어노테이션 이용한 설정

결합 완성품

Proxy : 결합의 완성품
         : Pointcut에 의해 핵심 TargetAdvice가 결합된 상태
         : 전체적인 결합체를 감싸고 있는 존재

            - Proxy는 내부적으로 Target을 호출하지만.
                  실행 시 중간에 필요한 관심사들을 거쳐서 Target 호출하도록 설계되어 있다.

[Pointcut의 주요 사용 설정]

execution (@execution) 메서드 기준으로 Pointcut 설정
within (@within) 특정 클래스 타입 기준으로 Pointcut 설정
this 주어진 인터페이스 구현 객체 기준으로 Pointcut 설정
args (@args) 특정 파라미터 가진 대상들만 기준으로 Pointcut 설정
@annotaion 특정 어노테이션 적용 대상들만 기준으로 Pointcut 설정

[Advice 동작 위치에 따른 분류]

Before Advice pointcut 메소드 호출 전 실행 - > Advice 실행 
After Returning Advice pintcut 메소드 익셉션 없이 실행 이후 - > Advice 실행 
After Throwing Advice pointcut 메소드 실행 도중 익셉션 발생 가능한 경우
                                                  - > Advice 실행 
After Advice (익셉션 발생여부와 관련X)
 pointcut 메소드 실행 후  - > Advice 실행 
Around Advice pointcut 메소드 실행 전/후  
또는 익셉션 발생 시점        - > Advice 실행 

[AOP 실습]

[공통 - AOP 설정 준비]

AspectJ Weaver 라이브러리가 가장 중요

pom.xml<aspectjweaver> 의존 추가 필요

스프링은 AOP 처리된 객체 생성 시 AspectJ Weaver라이브러리 도움 받아서 동작함


XML 이용AOP 구현 방법

[핵심 객체 준비] : Target 객체

public class TestBean { //Target 객체
	
	public int method1() {  //jointPoint 
		System.out.println("method1 호출");
		
		return 100;
	}
}

[관심사 객체 준비] : Advice (=Aspect) 객체

public class AdvisorClass { // (1) XML로 AOP 구현 시 '관심사 객체'
	
	public void beforeMethod() {
		System.out.println("beforeMethod 호출");
	}
	
	public void afterMethod() {
		System.out.println("afterMethod 호출");
	}
	
	public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("aroundMethod 호출1");
		
		// 원래의 메서드를 호출한다.
		Object obj = pjp.proceed();
		
		System.out.println("aroundMethod 호출 2");
		
		return obj;
	}
	
	public void afterReturningMethod() {
		System.out.println("afterReturningMethod 호출");
	}
	
	public void afterThrowingMethod(Throwable e1) {
		System.out.println("afterThrowingMethod 호출");
		System.out.println(e1);
	}

}

 

[XML 이용한 AOP 설정]

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	                    http://www.springframework.org/schema/beans/spring-beans.xsd
	                    http://www.springframework.org/schema/context
	                    http://www.springframework.org/schema/context/spring-context.xsd
	                    http://www.springframework.org/schema/aop
	                    http://www.springframework.org/schema/aop/spring-aop.xsd">
	                    
    <bean id='xml1' class='kr.co.softcampus.beans.TestBean'/>   //Target객체 빈 등록
	
	<bean id='advisor1' class='kr.co.softcampus.advisor.AdvisorClass'/> //Advice 빈 등록 
	
	<aop:config> // AOP 설정 
	<aop:aspect ref='advisor1'> 
		<aop:pointcut id="point1" expression="execution(* method1())"/>  //pointcut 설정
		
                      //동작 위치별 Advice 설정 	                                        
		<aop:before method="beforeMethod" pointcut-ref="point1"/>
		<aop:after method="afterMethod" pointcut-ref="point1"/>
		<aop:around method="aroundMethod" pointcut-ref="point1"/>			                          <aop:after-returning method="afterReturningMethod" pointcut-ref="point1"/>
		<aop:after-throwing method="afterThrowingMethod" pointcut-ref="point1" throwing="e1"/>
	</aop:aspect>
	</aop:config>      
</beans>

 

[실행 Main]

public class MainClass { //실행 메인

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ClassPathXmlApplicationContext ctx =
              new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
		                                                //xml 설정 컨테이터 생성
 
	TestBean bean1 = ctx.getBean("xml1", TestBean.class); // Target 빈 객체를 getBean()
		
	int a1 = bean1.method1(); //Target객체의 pointcut에 설정된 메소드 실행 

      //이때 beans.xml 설정 파일에 지정해놓은 Advice들이 동작 위치별로 핵심 로직과 함께 실행된다. 
		
		System.out.printf("a1 : %d\n", a1);
		
		ctx.close();
	}

}

[실행 결과 화면]


Java 설정 이용AOP 구현 방법

[핵심 객체 준비] : Target 객체

@Component //이 객체를 자동 빈 등록 
public class TestBean1 {

	public void method1()	{ // 얘를 핵심 Target객체의 jointPoint라고 생각해보자
		System.out.println("TestBean1의 method1() 호출");
	}
}

[관심사 객체 준비] : Advice (=Aspect) 객체

@Component  //우선 자동으로 빈 등록 설정 
@Aspect //얘를 관심사로 인식할 수 있게 지정
public class AdvisorClass {   // (2) Java 설정으로 AOP 구현 시 '관심사' 클래스
	
	@Before("execution(* method1())") 
	public void beforeMethod()	{
		System.out.println("beforeMethod()호출 ");
	}
	@After("execution(* method1())") 
	public void afterMethod() {
		System.out.println("afterMethod() 호출");
		
	}
	@Around("execution(* method1())")
	public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("aroundMethod 호출 1");
		Object result = pjp.proceed()	;
		System.out.println("aroundMethod 호출 2");
	
		return result; 
	}
	@AfterReturning("execution(* method1())")
	public void afterReturningMethod() {
		System.out.println("afterReturningMethod 호출 ");
	}
	
	@AfterThrowing("execution(* method1())")
	public void afterThrowingMethod() {
		System.out.println("afterThrowingMethod 호출");
	}
	
}

[Java 이용한 AOP 설정]

@Configuration
@ComponentScan(basePackages = {"kr.co.softcampus.beans", "kr.co.softcampus.advisor"})
@EnableAspectJAutoProxy //@AspectJ 이용해서 관심사로 등록해놓은 클래스를 자동으로 프록시 객체로 인식할 수 있게 설정 
public class BeanConfigClass {// 빈 설정 클래스


}

[실행 Main]

public class MainClass { // 실행 Main

	public static void main(String[] args) { 
		//Java 설정 파일로 컨테이너 객체 생성 
	AnnotationConfigApplicationContext ctx2 
                           = new AnnotationConfigApplicationContext(BeanConfigClass.class);

		TestBean1 java1 = ctx2.getBean(TestBean1.class);  //Target 객체 getBean
		java1.method1(); //pointcut된 메소드 실행
		  //실행 시, 동작 위치별로 관심사 Advice 지정해놓은 대로 실행됨
		
		ctx2.close();
	}

}

[실행 결과 화면]

728x90