Java/Spring

[Spring] 12 -2 AOP 적용하기 ( Annotation - Before, After, AfterReturning, AfterThrowing)

담크 2021. 7. 5. 17:30

이번엔 annotation을 사용하여 aop를 적용해보도록 하겠습니다.

com.test04 패키지 만들어주세요

Student.java (interface)

package com.test04;

public interface Student {
	
	public String classWork();

}

StudentA.java

package com.test04;

public class StudentA implements Student {

	@Override
	public String classWork() {
		System.out.println("컴퓨터를 켜서 뉴스를 본다.");
		return "스프링 연습";
	}

}

StudentB.java

package com.test04;

public class StudentB implements Student {

	@Override
	public String classWork() {
		System.out.println("컴퓨터를 켜서 주식을 본다.");
		return "스프링 연습";
	}

}

MyAspect.java

package com.test04;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyAspect {
	
	@Before("execution(public * *(..))")
	public void before(JoinPoint join) {
		System.out.println("출석한다.");
	}
	
	@After("execution(public * *(..))")
	public void after(JoinPoint join) {
		System.out.println("집에간다");
	}
	
	@AfterReturning(pointcut = "execution(public * *(..))", returning = "returnVal")
	public void returning(JoinPoint join, Object returnVal) {
		System.out.println(returnVal + "열심히 하는 날이었다.");
	}
	
	@AfterThrowing("execution(public * *(..))")
	public void throwing(JoinPoint join) {
		System.out.println("쉬는날이었다...");
	}

}

MTest.java

package com.test04;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class MTest {
	
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("com/test04/applicationContext.xml");
		
		Student a = factory.getBean("studentA", Student.class);
		Student b = (Student)factory.getBean("studentB");
		
		System.out.println("A 입장");
		a.classWork();
		System.out.println("--------------");
		System.out.println("B 입장");
		b.classWork();
	}

}

applicationContext.xml

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

	<aop:aspectj-autoproxy />
	
	<bean id="studentA" class="com.test04.StudentA" />
	<bean id="studentB" class="com.test04.StudentB" />
	<bean id="myAspect" class="com.test04.MyAspect" />
	
	
</beans>

코드 실행결과

 

이번엔 MyAspect에서 @를 이용한 annotation을 사용해서 aop를 적용해봤습니다.

먼저 appicationContext.xml에서 <aop:aspectj-autoproxy />를 사용해 필요한 상황에서 자동으로 프록시 객체를 생성하게 만들어줍니다.

 

그 이후에 4가지의 annotation을 사용하는데 각각은

@Before : 메소드 실행 전 시점

 

@After : 메소드 실행 후 시점 (메소드가 성공적으로 수행된 경우와 에러가 발생한 경우 모두 해당됩니다.)

 

@AfterReturning : 메소드가 에러 없이 성공적으로 실행된 이후의 시점

 

@AfterThrowing : 메소드가 에러가 발생하여 Exception을 던지는 시점

을 뜻합니다.

 

** @Around도 있긴하지만 여기서는 사용하지 않아서 용어 정리만 해보자면

@Around : 메소드의 시작부터 끝까지 전반적인 시점을 얘기합니다.

 

이 4가지의 annotation에서 저번 포스팅에서 설명했던 execution(public * *(..))를 사용했다는 것은 각각의 annotation들이 pointcut의 역할을 한다고 보면 됩니다.

 

만약 여기서 객체가 생성된 부분에 에러가 생긴다면 결과가 어떻게 바뀔까요?

StudentB에 그림과 같이 코딩하여 강제로 에러를 발생시켜 봤습니다.

A입장에서는 그대로 나오지만 B입장에서는 객체에서 에러가 발생했기 때문에 AfterReturning 부분이 아닌 AfterThrowing부분이 실행되어 에러 메시지와 출력되는 것을 볼 수 있습니다.