개발자 미니민의 개발스터디

[spring] AOP 란?

by mini_min
[spring] AOP 란?

✔️ AOP 

: 관점 지향 프로그래밍

핵심 비즈니스 로직과 공통 모듈을 분리하여 개발자가 좀 더 비즈니스 로직에만 집중해서 처리할 수 있는 방법을 제공한다. 

공통 모듈을 적용해서 발생하는 의존 관계의 복잡성과 코드 중복을 해소해주는 프로그래밍 기법이다.

즉, 공통 모듈을 별도로 작성하고 코드 밖에서 비즈니스 로직 사이에 삽입하는 것

 

📓 용어

- 타겟 : 핵심 기능을 담고 있는 모듈로 타겟은 공통 모듈을 부여할 대상이 된다. 

- 어드바이스 : 타겟에 제공할 공통 기능을 담고 있는 모듈이다. 

- 조인포인트 : 어드바이스가 적용될 수 있는 위치를 말한다.

타겟 객체가 구현한 인터페이스의 모든 메소드는 Join Point 가 된다.

- 포인트 컷 : 어드바이스를 적용할 타겟의 메소드를 선별하는 정규표현식이다.

- 애스펙트 : AOP 의 기본 모듈이다. (어드바이스+포인트컷) 

싱글톤 형태의 객체로 존재한다.

- 어드바이저 : 어드바이스 + 포인트컷

- 위빙 : 위빙은 포인트컷에 의해서 결정된 타겟의 조인 포인트에 어드바이스를 삽입하는 과정을 나타낸다.

 

📓 특징

- 스프링은 프록시 기반 AOP 를 지원한다. 

- 프록시가 호출을 가로챈다.

- 스프링 AOP 는 메소드 조인포인트만 지원한다. 

 

 

✔️ Advice 종류

- Before 어드바이스

: 타겟의 메소드 호출 전에 적용

- After 어드바이스

: 타겟의 메소드 호출 후에 적용

- After throwing

: 타겟의 예외 발생 후 적용

- After 

: 타겟의 메소드 호출 후 예외의 발생에 관계 없이 적용

- Around

: 타겟의 메소드 호출 이전과 이후 모두 적용

 

 

✔️ Before 어드바이스

-- Before 예시

✨ JdkRegexpMethodPointcut  : 포인트 컷

✨ BeforeLogAdvice : Before 어드바이스 클래스 (공통 부분 가지고 있음)

✨ DefaultPointcutAdvisor : Advice와 Pointcut 을 연결하는 작업

아래 코드에서는 write 메소드가 실행할 때 어떤 공통부분이 실행하는지 묶는 작업이다.

✨ 마지막에 AOP 를 적용한다 (타겟한테)

 

<!-- Target 클래스 : AOP를 적용할 대상 클래스이다. -->
<bean id="testServiceTarget" class="ex01.aop.before.TestServiceImpl"/>

<!-- Advice 클래스 : 공통사항을 가지고 있는 클래스 -->
<bean id="beforeAdvice" class="ex01.aop.before.BeforeLogAdvice"/>


<!-- Pointcut : 실제 Advice 가 적용될 Joinpoint(Advice가 적용될 시점) -->
<!-- 하나의 패턴 ,,,, write 라는 말이 들어간거 다 실행-->
<!--  -->
<!-- pattern : class 안에 있는 필드명이다!!! 이름 틀리면 xx -->
<!-- 
<bean id="myPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    <property name="pattern" value=".*write.*"/>
</bean>
 -->

 <!-- 다수의 패턴 -->
 <bean id="myPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    <property name="patterns">
        <list>
            <value>.*save.*</value>
            <value>.*write.*</value>	
        </list>
    </property>
 </bean>


<!-- Advisor : Advice와 Pointcut 을 연결하는 작업이다. -->
<!--  write 메소드가 실행할 때 어떤 공통부분이 실행하는지 묶는 것 -->
<bean id="testAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    <property name="advice" ref="beforeAdvice"/>
    <property name="pointcut" ref="myPointcut"/>
</bean>

<!-- 마지막 : AOP 적용하기 (타겟한테) -->
<!-- 기능이 +++ -->
<bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="testServiceTarget"/>
    <property name="interceptorNames">
        <list>
            <value>testAdvisor</value>
        </list>
    </property>
</bean>

 

✨ MethodBeforeAdvice : 대상 객체의 메소드를 실행하기 전에 공통 기능을 실행할 때 사용하는 Advice

//MethodBeforeAdvice
// 		: 대상 객체의 메소드를 실행하기 전에 공통 기능을 실행할 때 사용하는 Advice
public class BeforeLogAdvice implements MethodBeforeAdvice {

	@Override 			// 메소드, 매개변수, 타겟 
	public void before(Method method, Object[] args, Object target) throws Throwable {
		String s;
		
		s = target.getClass() + "클래스의 " + method.getName() + " 메소드 실행전에 실행...";
		s += "\n매개변수 : ";
		if(args != null) {
			for(int i = 0; i<args.length; i++) {
				s += args[i] + "  ";
			}
		}
		
		System.out.println(s);
		
	}

}
public class TestServiceImpl implements TestService {
	private String value;
	
	public  TestServiceImpl() {
		this.value = "AOP 테스트...";
	}
	
	@Override
	public void save(String value) {
		System.out.println("[save 메소드]...");
		this.value = value;
	}

	@Override
	public void write() {
		System.out.println("[wrtie 메소드]...");
		System.out.println(value);
	}
		
}

 

 

✔️ After 어드바이스

-- After 예시

<!-- Target 타겟 클래스 -->
<bean id="testServiceTarget" class="ex01.aop.after.TestServiceImpl"/>

<!-- Advice 클래스 -->
<bean id="afterAdvice" class="ex01.aop.after.AfterLogAdvice"></bean>

<!-- Advisor : Advice 와 Pointcut 연결하는 작업 -->
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice" ref="afterAdvice"/>
    <property name="patterns">
        <list>
            <value>.*save.*</value>
            <value>.*write.*</value>
        </list>
    </property>
</bean>

<!-- AOP 적용 -->
<bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="testServiceTarget"/>
    <property name="interceptorNames">
        <list>
            <value>myAdvisor</value>
        </list>
    </property>
</bean>

 

✨ AfterReturningAdvice : 대상 객체의 메소드 실행 이후에 공통 기능을 실행할 때 사용하는 Advice

예외가 없이 실행된 경우에만 실행

//AfterReturningAdvice
//	: 대상 객체의 메소드 실행 이후에 공통 기능을 실행할 때 사용하는 Advice
//	: 예외가 없이 실행된 경우에만 실행
public class AfterLogAdvice implements AfterReturningAdvice {

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		System.out.println(target + "클래스의 " + method.getName() + " 메소드 호출 후... ");
		System.out.println("리턴 값 : " + returnValue);
		
	}
	
}

 

 

✔️ MethodInterceptor

: MethodInterceptor 의 경우 세 가지 어드바이스를 묶은 어드바이스이다. (전 후 작업 다 할 수 있다!)

메소드 실행 전, 후 또는 예외 발생 시점에 공통 기능을 실행할 수 있다.

✨ MethodBeforeAdvice, AfterRunningAdvice, ThrowsAdvice 세가지 Advice를 하나로 묶은 Advice

 

📓 execution 명시자

: 엑시큐선은 어드바이스를 적용할 메소드를 명시할 때 사용한다.

형식 : execution(수식어패턴 리턴타입패턴 클래스이름패턴 이름패턴(파라미터패턴)) 예외패턴

패턴문자 : *(모든 값 표현) .. (0개 이상을 나타냄) 

 

✨ <property name="expression" value="execution(public * *(..))"/>

<!-- Target 클래스 -->
<bean id="testService" class="ex03.aop.interceptor.TestServiceImpl"/>

<!-- Advice 클래스 -->
<bean id="myLogAdvice" class="ex03.aop.interceptor.MyLogAdvice"/>

<!-- Advisor : execution 명시자에 표현식 기술 -->
<bean id="myAdvisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
    <property name="advice" ref="myLogAdvice"/>
    <property name="expression" value="execution(public * *(..))"/>
</bean>

<!-- AOP 적용 : 자동 프록시 생성기 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
public class MyLogAdvice implements MethodInterceptor {
//MethodInterceptor : 전 후 작업 다 할 수 있음
//	: 메소드 실행 전, 후 또는 예외 발생 시점에 공통 기능을 실행할 수 있다.
//  : MethodBeforeAdvice, AfterRunningAdvice, ThrowsAdvice 세가지 Advice를
// 	 	하나로 묶은 Advice
	
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		
		
		// 대상 객체 메소드 호출 전
		System.out.println(invocation.getMethod().getName()+ " 메소드 호출 전..");
		
		// 대상 객체 메소드 호출 
		Object returnValue = invocation.proceed();
		
		// 대상 객체 메소드 호출 후
		System.out.println(invocation.getMethod().getName()+ " 메소드 호출 후...");
		System.out.println("리턴값 : " + returnValue);
		
		return returnValue;
	}
	
}

 

 

 

 

 

블로그의 정보

개발자 미니민의 개발로그

mini_min

활동하기