본문 바로가기
국비학원

[국비지원] KH 정보교육원 114일차

by 도전하는 개발자 2022. 9. 8.

스프링의 양대 산맥 중 하나인 AOP에 대해 배워보자!!!


프로그래밍 패러다임의 한 종류
OOP - Object Oriented Programming - 객체 지향 프로그래밍
AOP - Aspect Oriented Programming - 관점 지향 프로그래밍

AOP
0) Aspect

구현해야할 핵심 비지니스 로직은 아니지만, 개발할 때의 관심사 (횡단관심사 Cross-Concern) (성능/속도, 자원사용효율성, 트랜잭션(All or Nothing), 로깅, 보안 등)

1) Advice
횡단 관심사(Cross-Concern)를 실제 구현한 객체 (ex) 트랜잭션 처리)

2) Target
핵심 비지니스 로직이 구현된 서비스 객체 (@Service, 비지니스 계층의 서비스) => 관심사들을 적용할 대상!

3) Jointpoint
Target 객체가 가지고 있는 메소드들 (ex) transfer 메소드 - 계좌이체)

4) Proxy (Target 객체 + Advice)
Target의 Joinpoint 수행시, 필요로하는 Advice들을 결합시켜 하나로 수행시키는 객체 (필수 조건 : 타입 메소드 모두 Target과 동일하게 갖추고 있어야함)

5) Pointcut
어느 Target의, 어느 JointPoint에 ,어떤Advice를 적용시킬지를 결정하는 방법(설정)

 

---

Advice의 종류


--

Pintcut



---

public interface SampleService {

	public abstract Integer doAdd(String op1, String op2) throws Exception;
	
} // end interface

SampleService

 

@Log4j2
@NoArgsConstructor

@Service
// 이 서비스 객체가 바로 AOP에서 말하는 Target 객체를 의미함!!!
// Target 객체 : 핵심 비지니스 로직을 메소드로 구현해 놓은 객체
public class SampleServiceImpl implements SampleService {

	@Override
	// 이 메소드가 AOP에서 말하는 JointPoint 메소드임!!!
	public Integer doAdd(String op1, String op2) throws Exception {
		log.info("doAdd({}, {}) invoked.", op1, op2);
		
		return Integer.parseInt(op1) + Integer.parseInt(op2);
	} // doAdd

} // end class

SampleServiceImpl

 

@Log4j2
@NoArgsConstructor

@Aspect    // Aspect를 구현한 것을 나타내기 위해 사용 (component scan을 통해 자동으로 빈으로 등록불가)
@Component // 스프링 빈으로 등록하기 위한 어노테이션 (AOP와는 무관)
public class LogAdvice {  // POJO : Plain Old Java Object

	
	// POINTCUT EXPRESSION 생성은, AsepectJ 언어에서 제공하는 함수를 이용
	// 이 pointcut 설정함수 이름은 "execution()"
	// 이 execution 함수를 호출시, pointcut 설정내역을 인자값으로 매개변수에 전달해야함  
	@Before( "execution( * org.zerock.myapp.service.*Service.*(..) )" )  
	// Service로 끝나는 모든 클래스의 모든 메서드의 모든 매개변수(..)에 적용
	public void logBefore() {
		log.trace("==============================");
		log.trace("logBefore() invoked.");
		log.trace("==============================");
		
	} // logBefore
	
} // end class

LogAdvice

 

@Log4j2
@NoArgsConstructor

//JUnit5 방식
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml" })

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(Lifecycle.PER_CLASS)
public class SampleServiceTests {

	// 주입
	@Setter(onMethod_=@Autowired)
	private SampleService service; 
	
	// 주입이 되었는지 1회성 전처리 과정을 통해 확인하자
	@BeforeAll
	void beforeAll() {
		log.trace("beforeAll() invoked.");
			
		// 주입이 되었는지 확인 (주입이 되었다면 null이 아님)
		assertNotNull(this.service);
		
		log.info("\t+ this.service : {}", this.service);
		log.info("\t+ type : {}", this.service.getClass().getName());
	} // beforeAll
	
	@Test
	@Order(1)
	@DisplayName("1. SampleService.testDoAdd")
	@Timeout(value = 10, unit = TimeUnit.SECONDS)
	void testDoAdd() throws Exception  {
		log.trace("testDoAdd() invoked.");
		
		int result = this.service.doAdd("100", "200");
		log.info("\t+ result : {}", result);
		
	} // testDoAdd

} // end class

SampleServiceTests

 

logAdvice가 먼저 실행되어 로그를 찍어준다 (인터셉터와 유사한 역할)

이로서 개발자는 핵심 로직에 집중할 수 있다.


---