스프링 프레임워크 (11) AOP (2) Advice(개념,Around, Before)

넙데데맨·2022년 5월 4일
0

AOP의 구현 시 필요한 구조

  • proxy
  • cross-cutting concern
  • 주 업무

Spring 없는 AOP

Proxy 클래스

실제 주 업무를 가진 클래스를 호출하게 된다.
사용자는 proxy를 호출하게 되고 사용하고 싶은 코드를 순서대로 삽입하면 된다.
굳이 본 코드에 Cross-Cutting Concern을 삽입하지 않아도 이런 방식을 사용하면 마치 삽입한 것처럼 사용이 가능하다.

Proxy를 Cross-Cutting Concern가 결합했다가 분리했다가 해야하기 위해 코드를 변경, 수정해야 하는 문제가 있다.
=> 스프링 DI를 사용해 해결할 수 있다.

Proxy의 예시
	public int total() {
		long start= System.currentTimeMillis();
		int result = kor+eng+math+com; // 주 업무
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		long end= System.currentTimeMillis();
		String message = (end-start) + "ms가 걸렸습니다.";
		System.out.println(message);
		return result;
	}

Cross-Cutting Concern을 따로 분리하기 위해 Proxy 사용

순수 Java로 구현한 AOP

Proxy 사용법

Proxy.newProxyInstance(
클래스.class, 클래스가 참조하는 인터페이스명, 
invocationHandler() 인터페이스를 구현하는 클래스)
NewlecExam.java
public int total() {

		int result = kor+eng+math+com;
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return result;
	}
Program.java
public static void main(String[] args) {
		Exam exam = new NewlecExam(1,1,1,1);
		
		Exam proxy = 
        (Exam) Proxy.newProxyInstance(NewlecExam.class.getClassLoader(), // 클래스
        new Class[] {Exam.class}, // 클래스 참조 인터페이스
        new InvocationHandler() { // 핸들러
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
            // Cross-Cutting Concern 삽입을 위한 메소드로 사용할 함수 명과 인자 값이 넘어오게 된다.
				long start= System.currentTimeMillis();	
				
				Object result = method.invoke(exam, args); // method.invoke(객체명,args) 사용할 주업무
				
				long end= System.currentTimeMillis(); 
				String message = (end-start) +
				"ms가 걸렸습니다."; 
				System.out.println(message);
				
				
				return result;
			}
		});
		
		System.out.printf("total is %d\n", exam.total()); //  proxy를 사용하지 않은 호출
        System.out.printf("total is %d\n", proxy.total()); //  proxy를 사용한 호출
	}


Cross-Cutting Concern이 필요할 시 proxy를 사용해서 함수를 호출해준다.

MethodInterceptor

프록시 객체의 콜백 기능 중 하나로, 프록시 객체에서 타겟 객체를 호출하기 전, 후로 비지니스 로직을 추가하거나, 타겟 클래스가 아닌 다른 객체의 메소드를 호출하거나, 인자 값을 변경할 수 있다.

구현 방법은 커스텀한 클래스에 MethodInterceptor 인터페이스를 상속받은 후 intercept 메서드를 오버라이드 한다.

Spring AOP 구현

기존 JAVA AOP

기본 자바 코드에서는

Proxy.newProxyInstance(
1. 클래스.class, 2. 클래스가 참조하는 인터페이스명,
3. invocationHandler() 인터페이스를 구현하는 클래스 )

newProxyInstance 함수를 통해 Proxy 객체를 만들어서 AOP를 구현하였다.
Spring에서는 1. 클래스3.invocationHandler() 구현만 해주면 2.클래스 참조 인터페이스는 스프링이 알아서 해결한다.

AroundAdvice 구현 예시

Program.java
public class Program {

	public static void main(String[] args) {
		ApplicationContext context = 
				new ClassPathXmlApplicationContext("spring/aop/setting.xml");
		
		Exam proxy = (Exam) context.getBean("proxy"); // proxy 빈 주입
		System.out.printf("total is %d\n", proxy.total());
		System.out.printf("avg is %f\n", proxy.avg());

	}

}
setting.xml
	<bean id="target" class="spring.aop.entity.NewlecExam" p:kor="1" p:eng="1" p:math="1" p:com="1"/>
    // 주 업무 빈
	<bean id="logAroundAdvice" class="spring.aop.advice.LogAroundAdivce"/>
    // 보조 업무 수행하는 crosscutting concern 빈
	<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> // proxy 빈
		<property name="target" ref="target"></property> // 주 업무 설정
		<property name="interceptorNames"> // 핸들러 역할
			<list> // 참조할 목록
				<value>logAroundAdvice</value> // crosscutting Corcern
			</list>
		</property>
	</bean>

org.springframework.aop.framework.ProxyFactoryBean 클래스 사용 시 target과 interceptorNames의 이름을 가진 property를 무조건 사용해야한다.

LogAroundAdvice.java
public class LogAroundAdvice implements MethodInterceptor { // AroundAdvice

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		long start= System.currentTimeMillis(); // 보조 업무
		
		Object result = invocation.proceed(); // 주 업무

		long end = System.currentTimeMillis(); // 보조 업무
		
		String message = (end-start) +"ms가 걸렸습니다."; System.out.println(message); // 보조 업무
		return result;
	}
	
	
}

MethodInvocation 타깃 오브젝트의 메소드를 내부적으로 실행

Advice 별 상속 받아야하는 메소드

Before - org.springframework.aop.MethodBeforeAdvice
Around - org.springframework.aop.MethodInterceptor
After Returning - org.springframework.aop.AfterReturningAdvice
After Throwing - org.springframework.aop.ThrowsAdvice

proceed() 메소드를 통해 주 업무를 result에 할당해준다.

BeforeAdvice 구현 예시

LogBeforeAdvice.java
public class LogBeforeAdvice implements MethodBeforeAdvice{ // Before Advice

	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println("BeforeAdvice");

	
	}
	
}

Before Advice는 무조건 주 업무 전에 실행되기 때문에 주 업무를 감쌀 필요가 없다.

profile
차근차근

0개의 댓글