무작정 개발.Vlog

[Spring3.0] AOP (관점 지향 프로그래밍)

by 무작정 개발
반응형
2022.03.28(65일 차)

 

이번에는 Spring AOP에 대해 정리할 것이다.

Spring Framework 구성 요소
Spring Framework 구성 요소

 

 

오늘의 수업 내용

 

AOP (Aspect Oriented Programming) - 관점 지향 프로그래밍

 

AOP Aspect Oriented Programming의 약자.

 

문제를 바라보는 관점을 기준으로 프로그래밍하는 기법이며, 관점 지향 프로그래밍이라 불린다.

  • 불특정 다수의 객체(클래스, 메서드)에 코드를 탈출할 수 있게 만드는 기능
  • 공통적으로 사용되는 부분(트랜잭션, 예외처리)을 별도로 분리하는 기술
  • 공통된 기능을 재사용하는 기법

 

1. 용어

 

횡단 관심사(Crosscutting Concerns)

  • 모든 영역에 공통적으로 적용
  • 모든 클래스를 가로로 관통하여 횡당 할 수 있는 관심사, 특정 클래스 혹은 메서드에 적용 가능
  • 중간중간 삽입되어야 할 기능들(로깅, 트랜잭션 등) / 주로 메서드 단위로 확인

조인 포인트(JoinPoint)

  • AOP에서 애플리케이션이 실행될 특정 지점을 의미
  • 어드바이스를 실행할 수 있는 지점 -> 포인트 컷의 후보

어드바이스(Advice)

  • 지정한 특정 조인 포인트에 실행할 코드
  • 종류 : before / after / after returning / after throwing / around

포인트 컷(PointCut)

  • 어드바이스를 실행하는 조인 포인트
  • 어드바이스를 실행하는 시간(위치)을 표시

에스 팩트(Aspect)

  • 어드바이스 + 포인트 컷
  • 어드바이스와 포인트 컷을 합쳐 횡단 관심사에 대한 코드와 이를 적용할 위치를 지정 (무엇을 언제 할지 정의)

 

출처 : https://wiper2019.tistory.com/167?category=786564
출처 : https://wiper2019.tistory.com/167?category=786564

 


 

AOP 예제 풀기

 

이제 예제를 활용하여 AOP의 개념을 잡아볼 것이다.

 

1. 레거시 프로젝트 생성

  • File -> New -> Legacy Project -> 프로젝트 이름 : SpringAop

 

2. AOP lib(라이브러리) 설치

  • 이전에 배운 Maven으로 라이브러리를 설치한다. 총 4개
  • pom.xml에 작성해서 자동으로 lib 추가

Spring AOP
Spring AOP
AspectJ Weaver
AspectJ Weaver
AspectJ Runtime
AspectJ Runtime
CGLib
CGLib

pom.xml

  • Spring AOP만 다른 lib랑 다르게 현재 쓰고 있는 스프링 버전을 맞춰야 해서
  • <version>{spring.framework.version}</version>
<!-- spring-aop -->
		<dependency>
   		 <groupId>org.springframework</groupId>
    		<artifactId>spring-aop</artifactId>
    		<version>${spring.framework.version}</version>
		</dependency>
		
		<!-- aspectjweaver -->
		<dependency>
    		<groupId>org.aspectj</groupId>
    		<artifactId>aspectjweaver</artifactId>
    		<version>1.8.10</version>
		</dependency>
		
		<!-- aspectjrt -->
		<dependency>
   		 	<groupId>org.aspectj</groupId>
   		 	<artifactId>aspectjrt</artifactId>
    		<version>1.8.10</version>
		</dependency>
		
		<!-- AOP Proxy cglib -->
		<dependency>
    		<groupId>cglib</groupId>
    		<artifactId>cglib</artifactId>
    		<version>3.2.4</version>
		</dependency>

 

3. 클래스 생성

  • 위치 : com/main/java > com.exe.aop
  • targetA, targetB 클래스 생성

 

targetA 클래스

package com.exe.aop;

public class TargetA {
	
	public void doSomething1() {
		System.out.println("TargetA.doSomething1");
	}
	
	public void doSomething2() {
		System.out.println("TargetA.doSomething2");
	}
	
	public void doAnother1() {
		System.out.println("TargetA.doAnother1");
	}
	
	public void doAnother2() {
		System.out.println("TargetA.doAnother2");
	}

}

 

targetB 클래스

package com.exe.aop;

public class TargetB {
	
	public void doSomething1(String str) {
		System.out.println("TargetB.doSomething1:" + str);
	}
	
	public void doSomething2() {
		System.out.println("TargetB.doSomething2");
	}
	
	public void doAnother1() {
		System.out.println("TargetB.doAnother1");
	}
	
	public void doAnother2() {
		System.out.println("TargetB.doAnother2");
	}

}

 

4. 실행할 시점에 따른 클래스 파일 생성 (MyBeforeAdvice 클래스 생성)

  • before : 메서드 호출 전
  • after : 메서드 호출 후
  • after returning : 메서드가 정상적으로 실행된 후
  • after throwing : 메서드를 실행하는 도중 에러가 발생하는 경우
  • around : before + after / 메서드 앞 뒤로 실행

위는 5개의 어드바이스 종류이다. 이 중에 before advice에 대해 정리해보겠다.

 

MyBeforeAdvice.java

package com.exe.aop;

public class MyBeforeAdvice {
	
	public void beforeMethodCall() {
		
		System.out.println("메서드 실행 전(BeforeAdvice)..");
	}

}

 

이제 app-context.xml로 넘어가서 작성을 해볼 것이다. 

  • expression="excution(public void com.. aop.*.*(..))"
  • excution(메서드 접근 지정자 반환 값 패키지 이름. 클래스 이름. 메서드 이름(매개변수)
  • (..) : 괄호 안의.. 은 뭐가 와도 상관없다는 뜻
  • com.. aop : com과 aop 사이에 있는.. 은  맨 앞은 com / 맨 뒤는 aop이고 중간은 뭐가 와도 상관없다는 뜻
<!-- 어드바이스 -->
<!-- 객체 생성 -->
<bean id="beforeAdvice" class="com.exe.aop.MyBeforeAdvice"/>
    
<!-- Before Advice -->
<aop:aspect ref="beforeAdvice"> <!-- ref : aspect를적용할 객체 -->
	<aop:pointcut id="beforePointcut" <!-- 실행할 행동 -->
		expression="execution(public void com..aop.*.*(..))" /> com.누구나.aop
	<aop:before method="beforeMethodCall"
		pointcut-ref="beforePointcut"/> <!-- 실행할 시점 -->
</aop:aspect>					<!-- method :  -->
						<!-- aop:pointcut의 id와 ref는 같아야 한다 -->

app-context.xml
app-context.xml

 

4. AopMain 클래스 생성

package com.exe.aop;

import org.springframework.context.support.GenericXmlApplicationContext;

public class AopMain {

	public static void main(String[] args) {
		
		GenericXmlApplicationContext context = 
				new GenericXmlApplicationContext("app-context.xml");
			
		TargetA ta = (TargetA)context.getBean("targetA");
		
		ta.doSomething1();
		ta.doSomething2();
		ta.doAnother1();
		ta.doAnother2();
		
	}

}

AopMain 실행 결과
AopMain 실행 결과

Main에 있는 4개의 각 메서드가 호출되기 전에 "메서드 실행 전(BeforeAdvice).."가 먼저 출력된다.

이게 BeforeAdvice이다.

 

위의 방법을 Annotation(어노테이션)으로 할 수 있다.


위의 예제를 Annotation(어노테이션)으로 변경하기

 

어노테이션으로 변경하면 코드가 매우 간결해진다.

먼저 app-content.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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/context 
	https://www.springframework.org/schema/context/spring-context-3.0.xsd
	http://www.springframework.org/schema/aop
	https://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

	<description>Example configuration to get you started.</description>

	<context:component-scan base-package="com.exe.aop" />
	
	<!-- 이번엔 하단에서 했던 노가다를  어노테이션으로 사용 -->
	<aop:aspectj-autoproxy/>
    
</beans>

처음에 했던 app-content.xml에서 사용한 코드는 지우고 <aop:aspectj-autoproxy/>만 작성하면 된다.

 

다음으로 MyBeforeAdvice 클래스를 변경해볼 것이다.

package com.exe.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect //객체를 IoT까지 실행 = <aop:aspect ref="beforeAdvice"> </aop:aspect>
@Component // bean 객체 생성 = <bean id="beforeAdvice" class="com.exe.aop.MyBeforeAdvice"/>
public class MyBeforeAdvice {
	
	//실행시점 및 적용할 메서드 지정
	@Before("execution(public void com..aop.*.*(..))")
	public void beforeMethodCall() {
		
		System.out.println("메서드 실행 전(BeforeAdvice)..");

	}

}

이렇게 어노테이션을 사용하면 손쉽게 작성할 수 있다. 어노테이션을 사용해도 이전에 나온 결과와 동일하게 출력된다.

 


더 많은 예제와 소스코드는 하단 GitHub 링크 참고

https://github.com/chaehyuenwoo/Spring3.0/tree/main/SpringAOP/src/main/java/com/exe/aop

 

GitHub - chaehyuenwoo/Spring3.0: Spring Framework 3.0버전_STS 3 IDE 사용

Spring Framework 3.0버전_STS 3 IDE 사용. Contribute to chaehyuenwoo/Spring3.0 development by creating an account on GitHub.

github.com

 

반응형

블로그의 정보

무작정 개발

무작정 개발

활동하기