Spring MVC, Sptring boot

[AOP] 관점지향 프로그래밍 (도서참고)

고인돌개발자 2021. 7. 3. 15:07

AOP Study by '스프링 입문을 위한 자바 객체지향의 원리와 이해 Chapter 07.


▶ Spring Documentation - https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop

 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io


▶ AOP (관점 지향 프로그래밍) by 위키피디아

더보기

컴퓨팅에서 관점 지향 프로그래밍(aspect-oriented programming, AOP)은 

횡단 관심사(cross-cutting concern)의 분리를 허용함으로써 모듈성을 증가시키는 것이

목적인 프로그래밍 패러다임이다.

코드 그 자체를 수정하지 않는 대신 기존의 코드에 추가 동작(어드바이스)을 추가함으로써 수행하며, "함수의 이름이 'set'으로 시작하면 모든 함수 호출을 기록한다"와 같이 어느 코드가 포인트컷(pointcut) 사양을 통해 수정되는지를 따로 지정한다.

이를 통해 기능의 코드 핵심부를 어수선하게 채우지 않고도 비즈니스 로직에 핵심적이지 않은 동작들을 프로그램에 추가할 수 있게 한다. 관점 지향 프로그래밍은 관점 지향 소프트웨어 개발의 토대를 형성한다.

관점 지향 소프트웨어 개발은 온전한 엔지니어링 분야를 가리키는 반면에 관점 지향 프로그래밍은 소스 코드 레벨에서 관심사들의 모듈화를 지원하는 프로그래밍 메서드들과 도구들을 포함하고 있다.

 

관심 지향 프로그래밍은 프로그램 로직을 명확한 부분들(이른바 "관심사")로 나누는 것을 수반한다.

거의 모든 프로그래밍 패러다임들은 관심사들을 별도의 독립적인 엔티티로 그룹화하고 캡슐화하는 것을 어느 정도는 지원하며, 이는 이러한 관심사들을 구현, 추상화, 합성하기 위해 사용할 수 있는 추상화(예: 함수, 프로시저, 모듈, 클래스, 메서드)를 제공함으로써 수행된다. 일부 관심사들은 프로그램 내의 여러 추상적 개념들에 영향을 미치며 이러한 형태의 구현체를 거역한다. 이러한 관심사들을 크러스 커팅 관심사(cross-cutting concerns)라고 부른다.

횡단 관심사의 전형적인 예로 로깅을 들 수 있는데 로깅 전략이 필연적으로 시스템 상에서 로그되는 모든 부분에 영향을 미치기 때문이다. 그러므로 로깅은 로그가 되는 모든 클래스들과 메서드들을 횡단한다.

모든 AOP 구현체들은 각각의 관심사를 한 자리에 캡슐화하는 횡단 표현식들을 일부 보유하고 있다. 구현체들 간의 차이점은 제공되는 생성자들의 권한, 보안, 사용성에 기인한다.

 


※ 서문 

    스프링 DI 가 의존성(new)에 대한 주입이라면 스프링 AOP는 로직(code) 주입이라 할 수 있다.

 


※ AOP 목적

"중복을 줄여서 적은 코드 수정으로 전체 변경을 할 수 있게 하자"

컴퓨팅에서 관점 지향 프로그래밍(aspect-oriented programming, AOP)은 횡단 관심사(cross-cutting concern)의 분리를 허용함으로써 모듈성을 증가시키는 것이 목적인 프로그래밍 패러다임이다. [위키피디아]

 


※ 코드 = 핵심 관심사 vs 횡단 관심사

    - 핵심 관심사 : 프로그램에서 말하고자 하는 핵심 Biz. 로직
    - 횡단 관심사 : 다수의 모듈에 공통으로 나타나는 부분 (각 로직의 DB Connectoin 같은 부분)

<횡단 관심사>

 


▶ 예제 시나리오 - 남자와 여자가 집에 들어가서 하는일

더보기

남자

열쇠로 문을 열고 집에 들어간다.

컴퓨터로 게임을 한다.

소등하고 잔다.

-------------------------------------------

예외사황처리: 집에 불남 - 119 에 신고한다.

 

여자

열쇠로 문을 열고 집에 들어간다.

요리를 한다.

소등하고 잔다.

-------------------------------------------

예외사황처리: 집에 불남 - 119 에 신고한다.

 

위 부분에서 빨강색 밑줄친 부분이 핵심 관심사 이며나머지

남자/여자 동일한 부분을 cross-cutting concerns (횡단 관심사) 라 한다. 

이 횡단 관심사를 Proxy pattern 으로 모듈화 하는것이 AOP 의 목적이다.

 

<시나리오 이미지>

 

▶ 예제 코드

더보기

Boy.java

 

public class Boy {

 public void runSomething() { 
 
  // 횡단 관심사
  System.out.println("열쇠로 문을 열고 집에 들어간다.");
  
  try {
  
  // 핵심 관심사
  System.out.println("컴퓨터로 게임을 한다.");
  
  } catch (Exception ex) {
    if(ex.getMessage().equals("집에 불남")) {
      // 횡단 관심사
      System.out.println("119 에 신고한다.");
    }   
  } finally {
  // 횡단 관심사
  System.out.println("소등하고 잔다.");
  }
  
  // 횡단 관심사
  System.out.println("자물쇠를 잠그고 집을 나선다.");
 }
}

 

--------------------------

 

Girl.java


public class Girl {

 public void runSomething() {

  // 횡단 관심사
  System.out.println("열쇠로 문을 열고 집에 들어간다.");

  try {

  // 핵심 관심사
  System.out.println("요리를 한다.");

  } catch (Exception ex) {
    if(ex.getMessage().equals("집에 불남")) {
      // 횡단 관심사
      System.out.println("119 에 신고한다.");
    }   
  } finally {
  // 횡단 관심사
  System.out.println("소등하고 잔다.");
  }

  // 횡단 관심사
  System.out.println("자물쇠를 잠그고 집을 나선다.");
 }
}

 

------------------------------------------

Start.java

 

public class Start {

public static void main(String[] args) {
Boy romeo  = new Boy();
Girl juliet = new Girl();

romeo.runSomething();

System.out.println();

juliet.runSomething();
}

 

-------------------------------

실행 

 

열쇠로 문을 열고 집에 들어간다.
컴퓨터로 게임을 한다.
소등하고 잔다.
자물쇠를 잠그고 집을 나선다.

열쇠로 문을 열고 집에 들어간다.
요리를 한다.
소등하고 잔다.
자물쇠를 잠그고 집을 나선다.


▶ 클래스의 메서드에서 로직이 주입 가능한 구간

더보기

 

<메서드에 로직(코드)을 주입할 수 있는 곳들

※ 위 예제에 Aop 적용해보기 

시나리오
  - Boy 메서드를 선언하는 Interface 를 생성한다.
  - Boy 에 핵심 관심사만 남긴다.

  - Aop 메서드를 하나 만든다.
  - Boy , Aop 를 Spring IoC 에 생성한다.

  - 위 내용을 실행할 main()을 생성한다.

 

더보기

  Person.java (interface)

public interface Person {
	void runSomething();
}

Boy.java , Girl.java ( 횡단 관심사를 지운다. )

// 횡단 관심사를 모두 지운다.
public class Boy implements Person {
	
	 @Override
	 public void runSomething() {
		 // 핵심 관심사
			  System.out.println("컴퓨터로 게임을 한다.");
	 }
}

// 횡단 관심사를 모두 지운다.
public class Girl implements Person {
	
	 public void runSomething() {
			  // 핵심 관심사
			  System.out.println("요리를 한다.");			
		 }
}

MyAspect.java (횡단 관심사를 넣는다.)

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect 
public class MyAspect {
	
    /* 특정 위치(패키지)의 메소드에서만 실행 */
	//@Before("execution(public void com.study.demo._team.aop.book.aop002.Boy.runSomething())")
   
    /* 해당 메서드는 모두 적용 */
    //@Before("execution(* runSomething())") // 모든 메서드 runSomething 을 사용하는 모든 위치

	/* Proxy pattern 사용 */ 
	//@Before("execution(public void com.study.demo._team.aop.book.aop002.Person.runSomething())")
	
	 @Before("execution(public void com.study.demo._team.aop.book.aop002.Boy.runSomething())")
	 public void before(JoinPoint joinPoint){
	  System.out.println("aop002.MyAspect. 얼굴 인식 확인: 문을 개방하라");
	  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
	 }

}

aop002.xml  (스프링 설정 파일을 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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 <aop:aspectj-autoproxy /> 
  <bean id="myAspect" class="com.study.demo._team.aop.book.aop002.MyAspect" />
  <bean id="boy"      class="com.study.demo._team.aop.book.aop002.Boy" />
  <bean id="girl"      class="com.study.demo._team.aop.book.aop002.Girl" />
</beans>

 Start.java  ( 실행 구문 )

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

public class Start {
	
public static void main(String[] args) {
		
		// Spring IoC 에 NyAspect, Boy 를 넣는다. xml 이용 
		ApplicationContext context = 
				 new FileSystemXmlApplicationContext("classpath:aop002/aop002.xml");
		  
		// Spring IoC 에서 boy, girl 를 가져온다.
		// 가져오는 값을 Person interface 를 사용한다. 
		 Person romeo  = (Person)context.getBean("boy", Person.class);
		 Person juliet = (Person)context.getBean("girl", Person.class);
		 
		  
		 // 실행 전 before MyAspect 실행
		 System.out.println("aop002.Boy ===> 실행 전 before MyAspect 실행");
		 romeo.runSomething();
		 
		 System.out.println();
		 
		 System.out.println("aop002.Girl ===> 실행 전 before MyAspect 실행");
		 juliet.runSomething();
	}

}

 

pom.xml ( Aop 적용을 위해 lib 를 추가한다. from Maven Repository ) 

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-aop</artifactId>
		    <!-- <version>2.5.1</version> -->
		</dependency>

 


※ 위 코드로 보는 AOP 의 설명 

 

위 코드에서 Boy.java 의 횡단 관심사는 제거되고 핵심 관심사만 남게되어 무척 심플한 코드가 되었다.
AOP 를 적용하면서 자연 Boy.java 에 단일책임원칙(SRP)을 자연스럽게 적용하게 되었다.
프로젝트시 한명의 개발자만 Aspect 관련 코딩을 하게되면 다른 개발자들은 부지불식간 그 혜택을 누리게 된다.
다른 개발자들은 횡단 관심사는 신경쓰지 않고 핵심 관심사만 코딩하면 된다.

 

 

▶ 스프링 AOP의 핵심 세가지
   1. 스프링 AOP는 인터페이스(interface) 기반이다.
   2. 스프링 AOP는 프록시(Proxy) 기반이다.
   3. 스프링 AOP는 런타임(runtime) 기반이다.

 


※ 용어설명 

더보기

※ 용어설명 

용어 영한 사전
Aspect 관점, 측면, 양상 
 - Advice들 + Pointcut 들
Advisor 조언자, 고문
  - 한 개의 Advice + 한 개의 Pointcut 
    * 스프링 AOP 에서만 사용하는 용어 (다른 프레임웍에서는 사용하지 않음)
Advice 조언,충고 
  - Pointcut 에 언제(When),무엇(What)을 적용할지 정의한 메서드
  - @Before 라는 시점에 before() 메서드를 실행하라고 조언함 (before 메서드는 변경가능)
 Action taken by an aspect at a particular join point  
  - Before , After returning , After throwing,  After (finally) , Around
Target 목표
  - 실질적인 비지니스 로직을 구현하고 있는 코드 , 행심관점에 해당함 (업무로직)
JoinPoint 결합점
  - 광의적의미 : Aspect 적용이 가능한 모든 지점
  - 협의적의미 : 호출된 객체의 메서드
  - Advice가 적용될 위치, 끼어들 수 있는 지점.
    메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용가능
 In Spring AOP, a join point always represents a method execution.
Pointcut 자르는 점  : JointPoint의 상세한 스펙을 정의
  -  횡단 관심사를 적용할 타깃 메서드(runSomething())를 선택하는 지시자
Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name)
<소스에서 용어 위치>

 


※ POJO 와 XML 기반 AOP

 - 스프링 프레임워크에 종속되지 않도록 소스를 수정한다.

 

▶ 소스코드 변경 

더보기

Boy.java , Girl.java , Person.java 기존과 동일

// 횡단 관심사를 모두 지운다.
public class Boy implements Person {
	
	 @Override
	 public void runSomething() {
		 // 핵심 관심사
			  System.out.println("aop003.컴퓨터로 게임을 한다.");
	 }
}

-----------------------------------------

//횡단 관심사를 모두 지운다.
public class Girl implements Person {
	
	 public void runSomething() {
			  // 핵심 관심사
			  System.out.println("aop003.요리를 한다.");			
		 }
}

-----------------------------------------

/* Proxy 패턴으로 사용되는 인터페이스 */
public interface Person {
	void runSomething();
}

 

MyAspect.java - 어노테이션 제거 ( xml 파일로 이동 )

import org.aspectj.lang.JoinPoint;

/* POJO & XML 기반 - 스프링 프레임워크에 종속되지 않음 */

public class MyAspect {
	 
	public void before(JoinPoint joinPoint){
	  System.out.println("aop003.얼굴 인식 확인: 문을 개방하라");
	  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
	 }
}

 aop003.xml - 어노테이션에 있던 내용을 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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 <aop:aspectj-autoproxy /> 
  <bean id="myAspect" class="com.study.demo._team.aop.book.aop003.MyAspect" />
  <bean id="boy"      class="com.study.demo._team.aop.book.aop003.Boy" />
  <bean id="girl"     class="com.study.demo._team.aop.book.aop003.Girl" />
  
  <aop:config>
  <aop:aspect ref="myAspect">   
   <aop:before method="before" pointcut="execution(* runSomething())" />
  </aop:aspect>
 </aop:config>
  
</beans>

 Start.java - 실행 구문 main()

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

public class Start {
	
	public static void main(String[] args) {
		
		// Spring IoC 에 NyAspect, Boy 를 넣는다. xml 이용 
		ApplicationContext context = 
				 new FileSystemXmlApplicationContext("classpath:aop003/aop003.xml");
		  
		// Spring IoC 에서 boy, girl 를 가져온다.
		// 가져오는 값을 Person interface 를 사용한다. 
		 Person romeo  = (Person)context.getBean("boy", Person.class);
		 Person juliet = (Person)context.getBean("girl", Person.class);
		 
		  
		 // 실행 전 before MyAspect 실행
		 System.out.println("aop003.Boy ===> 실행 전 before MyAspect 실행");
		 romeo.runSomething();
		 
		 System.out.println();
		 
		 System.out.println("aop003.Girl ===> 실행 전 before MyAspect 실행");
		 juliet.runSomething();
	}

}

 

 


▶ Pojo 를 사용한 After 

    - Boy.java, Girl.java, Person.java 는 기존과 동일 

더보기

   MyAspectPojo.java 

import org.aspectj.lang.JoinPoint;

/* POJO & XML 기반 - 스프링 프레임워크에 종속되지 않음 */

public class MyAspectPojo {
	 
	public void before(JoinPoint joinPoint){
	  System.out.println("aop004.얼굴 인식 확인: 문을 개방하라");
	  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
	 }
	
	public void lockDoor(JoinPoint joinPoint){
		  System.out.println("aop004.주인님 나갔다: 어이 문 잠가!!!");
		  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
		 }
		
}

StartPojo.java 

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

public class StartPojo {
	
	public static void main(String[] args) {
		
		// Spring IoC 에 NyAspect, Boy 를 넣는다. xml 이용 
		ApplicationContext context = 
				 new FileSystemXmlApplicationContext("classpath:aop004/aop004pojo.xml");
		  
		// Spring IoC 에서 boy, girl 를 가져온다.
		// 가져오는 값을 Person interface 를 사용한다. 
		 Person romeo  = (Person)context.getBean("boy", Person.class);
		 Person juliet = (Person)context.getBean("girl", Person.class);
		 
		  
		 // 실행 전 before MyAspect 실행
		 System.out.println("aop004pojo.Boy ===> 실행 전 before MyAspect 실행");
		 romeo.runSomething();
		 
		 System.out.println();
		 
		 System.out.println("aop004pojo.Girl ===> 실행 전 before MyAspect 실행");
		 juliet.runSomething();
	}

}

 

aop004pojo.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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 <aop:aspectj-autoproxy /> 
  <bean id="myAspect" class="com.study.demo._team.aop.book.aop004.MyAspectPojo" />
  <bean id="boy"      class="com.study.demo._team.aop.book.aop004.Boy" />
  <bean id="girl"     class="com.study.demo._team.aop.book.aop004.Girl" />
  
  <aop:config>
  <aop:aspect ref="myAspect">   
   <aop:before method="before"   pointcut="execution(* runSomething())" />
   <aop:after  method="lockDoor" pointcut="execution(* runSomething())" />
  </aop:aspect>
 </aop:config>
  
</beans>

 

▶ 어노테이션 기반 After 

    - Boy.java, Girl.java, Person.java 는 기존과 동일 

더보기

MyAspect.java

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

@Aspect 
public class MyAspect {
	
    /* 특정 위치(패키지)의 메소드에서만 실행 */
	//@Before("execution(public void com.study.demo._team.aop.book.aop002.Boy.runSomething())")
    
    /* 해당 메서드는 모두 적용 */
    @Before("execution(* runSomething())") // 모든 메서드 runSomething 을 사용하는 모든 위치
	 public void before(JoinPoint joinPoint){
	  System.out.println("aop004.얼굴 인식 확인: 문을 개방하라");
	  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
	 }
    
    
    /* 해당 메서드는 모두 적용 */
    @After("execution(* runSomething())") // 모든 메서드 runSomething 을 사용하는 모든 위치
	 public void lockDoor(JoinPoint joinPoint){
	  System.out.println("aop004.주인님 나갔다 : 어이 문 잠가 !!!");
	  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
	 }
    

}

 

Start.java

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

public class Start {
	
	public static void main(String[] args) {
		
		// Spring IoC 에 NyAspect, Boy 를 넣는다. xml 이용 
		ApplicationContext context = 
				 new FileSystemXmlApplicationContext("classpath:aop004/aop004.xml");
		  
		// Spring IoC 에서 boy, girl 를 가져온다.
		// 가져오는 값을 Person interface 를 사용한다. 
		 Person romeo  = (Person)context.getBean("boy", Person.class);
		 Person juliet = (Person)context.getBean("girl", Person.class);
		 
		  
		 // 실행 전 before MyAspect 실행
		 System.out.println("aop004.Boy ===> 실행 전 before MyAspect 실행");
		 romeo.runSomething();
		 
		 System.out.println();
		 
		 System.out.println("aop004.Girl ===> 실행 전 before MyAspect 실행");
		 juliet.runSomething();
	}

}

aop004.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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 <aop:aspectj-autoproxy /> 
  <bean id="myAspect" class="com.study.demo._team.aop.book.aop004.MyAspect_Refactoring" />
  <bean id="boy"      class="com.study.demo._team.aop.book.aop004.Boy" />
  <bean id="girl"     class="com.study.demo._team.aop.book.aop004.Girl" />
  
</beans>

 

MyAspect.java  공통부분 Refactoring

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

@Component
@Aspect 
public class MyAspect_Refactoring {
	
    /* Pointcut 공통부분으로 정의 */
	@Pointcut("execution(* runSomething())") 
	private void iampc() {
		// 여긴 무엇을 작성해도 의미가 없어요.
	}
	
   
    @Before("iampc()") // 모든 메서드 runSomething 을 사용하는 모든 위치
	 public void before(JoinPoint joinPoint){
	  System.out.println("aop004-Refactoring.얼굴 인식 확인: 문을 개방하라");
	  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
	 }
    
    
    /* 해당 메서드는 모두 적용 */
    @After("iampc()") // 모든 메서드 runSomething 을 사용하는 모든 위치
	 public void lockDoor(JoinPoint joinPoint){
	  System.out.println("aop004-Refactoring.주인님 나갔다 : 어이 문 잠가 !!!");
	  //System.out.println("열쇠로 문을 열고 집에 들어간다.");
	 }
    

}
	

 


※ 스프링 AOP 를 적용할 수 있는 시점(advice)은 총 5가지 

AOP 적용 시점 설명
Before  어드바이스 타겟 메소드가 호출되기 전에 어드바이스 기능을 수행
After    타겟 메소드의 결과에 관계없이(즉 성공, 예외 관계없이) 타겟 메소드가 완료 되면 어드바이스 기능을 수행
AfterReturning   (정상적 반환 이후)
타겟 메소드가 성공적으로 결과값을 반환 후에 어드바이스 기능을 수행
AfterThrowing (예외 발생 이후)
타겟 메소드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행
Around  (메소드 실행 전후)
어드바이스가 타겟 메소드를 감싸서 타겟 메소드 호출전과 후에 어드바이스 기능을 수행

 

※ 포인트 컷 표현식 

더보기
Pointcut      -->                선택된 Joinpoints

execution(public * *(..))  -->   public 메소드 실행

execution(* set*(..))   -->      이름이 set으로 시작하는 모든 메소드명 실행

execution(* com.xyz.service.AccountService.*(..))   
     -->  AccountService 인터페이스의 모든 메소드 실행

execution(* com.xyz.service.*.*(..))   -->  service 패키지의 모든 메소드 실행

execution(* com.xyz.service..*.*(..))  -->   service 패키지와 하위 패키지의 모든 메소드 실행

within(com.xyz.service.*)   -->    service 패키지 내의 모든 결합점 (클래스 포함)

within(com.xyz.service..*)  -->    service 패키지 및 하위 패키지의 모든 결합점 (클래스 포함)

this(com.xyz.service.AccountService)
    -->   AccountService 인터페이스를 구현하는 프록시 개체의 모든 결합점

target(com.xyz.service.AccountService)            
    -->   AccountService 인터페이스를 구현하는 대상 객체의 모든 결합점

args(java.io.Serializable)                               
   -->    하나의 파라미터를 갖고 전달된 인자가 Serializable인 모든 결합점

@target(org.springframework.transaction.annotation.Transactional)   
   -->    대상 객체가 @Transactional 어노테이션을 갖는 모든 결합점

@within(org.springframework.transaction.annotation.Transactional)   
   -->  대상 객체의 선언 타입이 @Transactional 어노테이션을 갖는 모든 결합점

@annotation(org.springframework.transaction.annotation.Transactional)
   -->  실행 메소드가 @Transactional 어노테이션을 갖는 모든 결합점
    
@args(com.xyz.security.Classified)
   -->  단일 파라미터를 받고, 전달된 인자 타입이 @Classified 어노테이션을 갖는 모든 결합점

bean(accountRepository)  -->       “accountRepository” 빈

!bean(accountRepository)  -->      “accountRepository” 빈을 제외한 모든 빈

bean(*)       -->    모든 빈

bean(account*)   -->      이름이 'account'로 시작되는 모든 빈

bean(*Repository)   -->      이름이 “Repository”로 끝나는 모든 빈

bean(accounting/*)    -->        이름이 “accounting/“로 시작하는 모든 빈

bean(*dataSource) || bean(*DataSource) 
     --> 이름이 “dataSource” 나 “DataSource” 으로 끝나는 모든 빈

 출처: https://devjms.tistory.com/70 [얼렁뚱땅 개발자]

※ 하나 더 알아두기

자바 or Spring 에서 AOP 의 적용은 Bean (Srping IoC 에 loading 된 객체) 만 적용이 된다. 

즉 일반 자바에서는 적용이 안된다.

 


참고서적 : 스프링 입문을 위하 자바 객체지향의 원리와 이해