본문 바로가기
Java Web Programming/6. Spring | MyBatis

[Spring] 스프링 AOP 개념 이해와 적용 방법 (+Proxy 프록시)

by 파프리카_ 2020. 10. 28.
728x90
반응형

[ AOP 란? ]

" AOP란 OOP를 더 OOP 답게!"

 

: Aspect Oriented Programming = 관점 지향 프로그래밍

 

> AOP 적용 전

 

> AOP 적용 후

*위빙 : 횡단 관심 사항을 엮어준다.

 

* Aspect : 관점 ! 

시스템을 두 가지 관점으로 나누어 본다.

시스템을 핵심관심사(Core Concern)횡단관심사(Cross-cutting Concern)로 구분하여 설계와 구현을 한다

  • 핵심관심사(Core Concern)란 시스템의 목적에 해당하는 주요 로직 부분을 말한다
  • 횡단관심사(Cross-cutting Concern)란 시스템의 여러 부분에 걸쳐 공통적이고 반복적으로 필요로 하는 처리내용을 말한다
  • AOP는 시스템의 여러 영역에 걸쳐 공통적이고 반복적으로 적용된 횡단관심사(Cross-Cutting Concern)를 분리하여,
    별도의 모듈에서 설계, 구현,운영하는 프로그래밍 기법이다
  • 대표적인 횡단관심사는 로깅, 보안, 트랙잭션 관리, 예외 처리등이 있다

장점

: AOP를 적용하면,

핵심관심사항 서비스를 제외한 횡단관심사항 서비스를 별도의 모듈에서 개발하여 적용하므로,

여러 서비스에 걸쳐있는 반복적 작업을 줄일 수 있어 생산성이 높아진다.

이후 요구사항 변경 시에도 유연하게 대처할 수 있으므로, 유지보수성이 높아진다.

 

사용 방법 - aop-ioc.xml

1. 횡단 관심 사항을 정의

2. IOC 기반 하에, AOP 설정을 pointcut으로 적용대상을 지정

3. advice로 횡단괌심사항 서비스 적용 시점을 지정한다.


[ AOP 사용 환경 설정 ]

> pom.xml에 라이브러리 추가

<!-- AOP Library -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.1</version>
</dependency>

 

> Spring AOP Pointcut AspectJ 표현식 (XML 기반)

 

executeion([returnType]  [package].[className].[methodName] ([매개변수리스트] ))

execution( * com.exam.*Service.find*(..))

: com.exam 하위의 Serivce로 마치는 클래스의 리턴타입 유형에 관계없이,

find 로 시작하는 메서드명을 가진 매개변수 0~* 인 메서드를 AOP 적용대상으로 한다

 

[ 사용 예 ]

  • execution(String com.exam.service..*.search*(..))
    com.exam.service 패키지 또는 그 하위 패키지의 모든 클래스 중 String 리턴타입인 search 이름으로 시작하는 모든 메서드를 적용대상으로 한다
  • within(com.exam.service.*)
    com.exam.service 패키지 하위의 모든 클래스의 모든 메서드를 대상으로 한다
  • bean(*Service)
    IOC 컨테이너에 관리되는 bean이름이 Service로 끝나는 bean의 모든 메서드를 대상으로 한다

[ AOP 주요 용어 ]

Aspect AOP의 단위가 되는 횡단관심사를 의미 ex) 로깅,트랜잭션관리 등
JoinPoint 횡단관심사가 실행될 지점
Advice 횡단관심사를 처리하는 부분, 특정 JoinPoint에서 실행되는 코드로서 before, after returing , after throwing, after , around advice가 있다
Pointcut 여러 JoinPoint 중 실제 어드바이스를 적용할 곳을 선별하기 위한 표현식
Weaving 애플리케이션의 적절한 지점에 aspect를 적용하는 것을 말함
Target Aspect 가 적용된 객체를 말한다

 

[ AOP Advice 유형 ]

  • Before : 메서드 실행 전에 실행하는 Advice
  • After Returning : 메서드 정상 실행 후 실행하는 Advice
  • After Throwing : 메서드 실행시 예외 발생시 실행하는 Advice
  • After : 메서드 정상 실행 또는 예외 발생 상관없이 실행하는 Advice
  • Around :  위 네가지 Advice를 모두 포함 , 모든 시점에서 실행할 수 있는 Advice

[ AOP 주요 디자인 패턴 ] 

> Proxy(프록시) Design Pattern

- AOP 적용 시에는 동일한 인터페이스를 implements 하는 Proxy 객체가 반환된다 (Delegate : 대리한다)

- ex)

<<interface>>Subject = <<interface>> BoardSerivce 

RealSubject = BoardServiceImpl

 

Spring AOP Proccess

출처 : https://www.baeldung.com/spring-aop-vs-aspectj


[ 적용 예제 ]

기존 시스템은 MemberService의 다수 메서드와 BoardService의 다시 메서드가 실행 중인 상태

-> 요구사항 : 각 서비스의 메서드에서 수행완료 시간을 특정 파일에 기록하도록 추가 요구사항이 들어왔다.

 

1) AOP 적용 X : 각 서비스 클래스의 모든 메서드 각각에, 공통된 작업을 직접 코딩을 하여 추가해야 한다.

 

2) AOP 적용 O

: 시스템을 '핵심 관심사항'과 '횡단 관심사항'으로 구분하여,

공통된 작업(추가요구사항)은 별도의 모듈에서 기능을 정의한 후,

대상과 시점을 지정하여 생산성있게 개발할 수 있다.


/BoardService.java <<interface>>

package model;

public interface BoardService {
	public void registerInfo(String info);
	public void getContentByNo(String no);
	public void deletePostByNo(String no);
}

 

/BoardServiceImpl.java 

- core 핵심 사항 : registerInfo / getContentByNo / deletePostByNo

- 그 외 많은 메서드있다고 가정

package model;

public class BoardServiceImpl implements BoardService {

	@Override
	public void registerInfo(String info) {
		// core 핵심 관심 사항
		System.out.println("BoardService registerInfo: "+ info);
	}

	@Override
	public void getContentByNo(String no) {
		// core 핵심 관심 사항
		System.out.println("BoardService getContentByNo: "+ no);
	}

	@Override
	public void deletePostByNo(String no) {
		// core 핵심 관심 사항
		System.out.println("BoardService deletePostByNo: "+ no);
	}
	
	// 그 외 많은 메서드가 있다고 가정..
}

/MemberService.java <<interface>>

package model;

public interface MemberService {
	//interface는 접근제어가의 default가 public이다.
	public void updateMember();
	public void deleteMember();
	public void getAllMember();
}

 

/MemberServiceImpl.java

- core 핵심 사항 : updateMember / deleteMember / getAllMember

- 그 외 많은 메서드있다고 가정

package model;

public class MemberServiceImpl implements MemberService {
	@Override
	public void updateMember() {
		//core 핵심 관심 사항
		System.out.println("MemberService updateMember");
	}
	
	@Override
	public void deleteMember() {
		//core 핵심 관심 사항
		System.out.println("MemberService deleteMember");
	}

	@Override
	public void getAllMember() {
		//core 핵심 관심 사항
		System.out.println("MemberService getAllMember");
	}
	
	// 그 외 많은 메서드가 있다고 가정..
}

횡단 관심 사항을 정의하는 클래스 - AOP 적용!
(Logging : 대상 메서드가 실행완료 후, 시간 정보를 특정 공간에 기록하는 서비스)

 

/CommonLoggingService.java

package aop.common;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
/*
 * 횡단 관심사항을 정의한 클래스
 */
public class LoggingService {
	//Log4j를 사용하기 위한 선언부
	Logger log = LogManager.getLogger(LoggingService.class);

	public void beforeLogging(JoinPoint point) {
		//횡단 관심 사항을 적용할 대상 class의 이름
		String className = point.getTarget().getClass().getName();
		//횡단 관심 사항을 적용할 대상 메서드의 이름
		String methodName = point.getSignature().getName();
		
		//System.out.println(className+" "+methodName);
		log.info(className + " "+ methodName);
	}
}

횡단 관심 사항 서비스 정의한 bean + AOP 적용 

1. 횡단 관심 사항을 정의

2. IOC 기반 하에, AOP 설정을 pointcut으로 적용대상을 지정

3. advice로 횡단괌심사항 서비스 적용 시점을 지정한다.

 

/ioc-aop.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.xsd">
	
	<bean id="boardService" class="model.BoardServiceImpl"></bean>
	<bean id="memberService" class="model.MemberServiceImpl"></bean>
	
	<!-- 횡단 관심 사항 서비스를 정의한 bean -->
	<bean id="commonLogging" class="aop.common.CommonLoggingService"></bean> 

	<!-- AOP 설정 -->
	<aop:config>
		<!-- 1. 횡단관심사항을 정의한 bean -->
		<aop:aspect ref="commonLogging">
			<!-- 2. pointcut : 횡단 관심사항 적용 대상을 지정
			 	<aop:pointcut expression="execution([접근제어자] [returnType] [package].[className].[methodName].([number])" id="[id]"/> -->
			<aop:pointcut expression="execution(public * model.*Service.*(..))" id="pt"/>
			<!-- 3. Advice : 횡단관심사항 서비스가 어느 시점에 적용될 것인가 지정
			    - after : 메서드 실행 완료 후 지정됨( 정상 실행 또는 예외 발생 상관X) 
				<aop:after method="[횡단관심사항bean id]" pointcut-ref="[pointcut id]"/>
			 -->
			<aop:after method="timeLogging" pointcut-ref="pt"/>
		</aop:aspect>
	</aop:config>
	
</beans>

/testController.java

package test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import model.BoardService;
import model.MemberService;

public class TestController {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext factory
			= new ClassPathXmlApplicationContext("ioc-aop.xml");
		
		//boardSerivce 받아보기
		BoardService bs = (BoardService) factory.getBean("boardService");
		bs.deletePostByNo("1");
		bs.getContentByNo("1");
		bs.registerInfo("milk");
		
		System.out.println("-------------------------");
		
		//memberService 받아보기
		MemberService ms = (MemberService) factory.getBean("memberService");
		ms.deleteMember();
		ms.getAllMember();
		ms.updateMember();
		
		factory.close();
		
	}
}

[ 결과 ]

728x90
반응형