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

[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

활동하기