본문 바로가기

Programming/Java

Spring AOP(Aspect Oriented Programming) Sample

// Application.java

package com.example.demo;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.FileSystemResource;

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		BeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
		MessageBean bean = (MessageBean)factory.getBean("proxy"); // ProxyFactoryBean 클래스를 인수로 지정
		bean.sayHello();
	}
}

// MessageBean.java

package com.example.demo;

public interface MessageBean {
	void sayHello();
}

// MessageBeanImpl.java

package com.example.demo;

public class MessageBeanImpl implements MessageBean {

	private String name;
	
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public void sayHello() {
		try {
			Thread.sleep(5000); //Advice가 실행하는 로그 출력에 처리 시간을 포함하기 위해 Thread.sleep() 메서드를 사용해서 의도적으로 처리시간을 늦추는 부분
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Hello, " + name + "!" );
	}
}

// LoggingAdvice.java

package com.example.demo;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.util.StopWatch;

// LoggingAdvice 클래스는 MessageBeanImpl 클래스의 sayHello() 메서드 호출 전후 로그 출력 처리를 위빙하는 "Around Advice"
// Advice Type이 Around Advice면 org.springframework.aop.MEthodInterceptor 인터페이스를 구현해야 함
public class LoggingAdvice implements MethodInterceptor { // MethodInterceptor 인터페이스 구현
	
	// invoke() 메서드는 대상인 메서드 호출시에 가동되는 메서드
	// 인수로는 org.aopappliance.intercept.Joinpoint 인터페이스를 구현하는 클래스를 받습니다.
	// Joinpoint(Interface) <- Invoation(Interface) <- MethodInvoation(Interface)
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		String methodName = invocation.getMethod().getName();
		StopWatch sw = new StopWatch(); // 스톱워치 기능을 제공하는 스프링 유틸리티 클래스
		
		sw.start(methodName);
		
		// sayHello() 메서드가 호출되면, invoke() 메서드 호출
		// 아래 코드는 sayHello() 메서드 실행 전에 실행
		System.out.println("[LOG] METHOD : " + methodName + " is calling.");
		Object rtnObj = invocation.proceed(); // proceed() 메서드가 호출되었을 때, 대상인 sayHello() 메서드가 실행
		
		sw.stop();
		
		// sayHello() 메서드 호출이 종료된 후 실행
		System.out.println("[LOG] METHOD : " + methodName + " was called.");
		System.out.println("[LOG] 처리시간 : " + sw.getTotalTimeMillis() / 1000 + "초");
		
		return rtnObj; // 반환 값으로 MethodInvoation 클래스의 proceed() 메서드의 반환 값인 Object 타입의 인스턴스를 리턴
	}
}

결과
[LOG] METHOD : sayHello is calling.
Hello, Spring!
[LOG] METHOD : sayHello was called.
[LOG] 처리시간 : 5초