SpringBoot | AOP와 횡단관심사

새니·2023년 7월 11일

SpringBoot

목록 보기
2/7
post-thumbnail

Aop란?

AOP(Aspect-Oriented Programming)는 스프링 프레임워크에서 제공하는 기능 중 하나로, 애플리케이션의 핵심 로직과는 별개로 여러 모듈에서 공통적으로 사용되는 기능들을 분리하여 모듈화하는 프로그래밍 패러다임. AOP는 핵심 로직에 영향을 주지 않으면서, 여러 모듈에서 반복적으로 사용되는 기능들을 재사용하고 관리하기 쉽게 만들어준다.


AOP(Aspect-Oriented Programming)는 관점(Aspect)조언(Advice) 이라는 개념이 있다.

- Aspect(관점)

관점은 애플리케이션에서 특정 기능을 구현한 모듈
애플리케이션의 여러 부분에 걸쳐서 반복적으로 사용되는 기능들을 추상화하여 모듈화한 것이다.

- Aspect Expression

  1. execution(* *(..)) => 접근 가능한 모든 메소드가
    point cut
  2. execution( test.service..*(..))
    => test.service 패키지의 모든 메소드 point cut
    -> 리턴타입은 상관없다
  3. execution(void insert*(..))
    =>리턴 type 은 void 이고 메소드명이
    insert 로 시작하는 모든 메소드가 point cut
  4. execution( delete(*))
    => 메소드 명이 delete 로 시작하고 인자로 1개 전달받는
    메소드가 point cut (aop 가 적용되는 위치)
  5. execution( delete(,))
    => 메소드 명이 delete 로 시작하고 인자로 2개 전달받는
  6. execution(String update(Integer,))
    => 메소드 명이 update 로 시작하고 리턴 type 은 String
    메소드의 첫번째 인자는 Integer type, 두번째 인자는 아무 type 다되는
    메소드가 point cut (aop 가 적용되는 위치)

-조언(Advice)

조언은 관점이 적용되어야 할 지점을 지정하고, 해당 지점에서 실행되어야 할 코드
조언은 관점이 특정 시점에 어떻게 동작해야 하는지를 결정한다.



횡단 관심사란 ?

애플리케이션의 핵심 로직과는 별개로 여러 모듈에서 공통적으로 발생하는 기능.
여러 메서드에서 로깅을 수행해야 한다면 각 메서드마다 로깅 코드를 중복해서 작성해야한다. 이런 경우, 횡단 관심사를 분리하여 모듈화할 수 있으면 코드 중복을 줄이고 유지보수성을 향상시킬 수 있다.

AOP를 사용하면 횡단 관심사를 중앙에서 관리하여 코드 중복을 줄이고 유지보수성을 향상시킬 수 있습니다. 또한, 횡단 관심사의 변경이나 추가가 필요할 때도 핵심 로직에 영향을 주지 않고 AOP 설정을 변경함으로써 쉽게 대응할 수 있습니다. 이는 애플리케이션의 유연성과 확장성을 높여줍니다.



😊 예시를 통해서 알아보기

[ pom.xml ]

  • aop를 사용하기 위해 필요한 라이브러리 추가해준다!

[writingUtil]

  • writionUtil의 wirteLetter, writeReport, wirteDiary 메소드가 존재한다.
    이 메소드에는 중요 기능 이외에 파란색pen을 준비해요 , pen을 닫고 마무리 해요! 의 기능이 중복되는 것을 확인 할 수 있다.

이 중복되는 기능을 횡단 관심사이며, 이 코드를 분리하여 모듈화 한다면 코드가 훨씬 간결해질것이다!

[WritingAspect]


@Aspect
@Component  //bean으로 만들기 위한 어노테이션
public class WritingAspect {
	@Before("execution(void write*())")
	public void prepare() {
		System.out.println("파란색 pen을 준비해요!");
	}
	
	@After("execution(void write*())")
	public void end() {
		System.out.println("pen을 닫고 마무리 해요 ! ");
	}
}

  • spring이 관리하는 bean 의 메소드가 수행되기 이전(before)에 적용되는 aspect

  • @Before와 @After로 메소드의 실행 시점을 정할 수 있다!

    	  [메소드 pattern]
    	 * 리턴 type => void
    	 * 메소드명 =>  write로 시작하는 메소드
    	 * 메소드의 매개변수 => 없음
     
    	 * Aspect가 적용되는 위치를 "point cut"이라고 한다. 
    	  : wirte라는 모든 메소드가 실행되기전에 적용해라
     

😊결과

😊 예시를 통해서 더 나아가기 !

[message]

  • sendGreeting 메소드와 getMessage 메소드를 만들어준다.

[MessageAspect]


@Around("execution(void send*(..))")
	public void checkGreeting(ProceedingJoinPoint joinPoint) throws Throwable {
		//메소드에 전달된 인자들 목록을 얻어내기
		Object[] args=joinPoint.getArgs();
		for(Object tmp:args) {
			//만일 String type 이면
			if(tmp instanceof String) {
				//원래 type 으로 casting
				String msg=(String)tmp;
				System.out.println("aspect 에서 읽어낸 내용:"+msg);
				if(msg.contains("안녕하세요")) {
					System.out.println("안녕하세요 금지된 단어 입니다.");
					return; // 메소드를 끝내기
				}
			}
		}
		//aspect 가 적용된 메소드가 호출 되기 직전에 할 작업은 proceed() 호출전에 한다.		
		// proceed() 를 호출해야 aspect 가 적용된 메소드가 실행이된다.
		joinPoint.proceed();
		
		//aspect 가 적용된 메소드가 호출 되기 직전에 할 작업은 proceed() 호출 이후에 한다.		
		System.out.println("aspect 가 적용된 메소드가 리턴 했습니다.");
	}
  • @Around : before , after 모두 사용 가능한 어노테이션이다.
  • send 메소드가 호출 될 때 만약 msg에 "안녕하세요" 라는 단어가 있다면
    "안녕하세요 금지된 단어입니다" 를 리턴하고, 그렇지 않다면 aspect에서 읽어낸 내용을 출력한다!

결과 👍

@Around("execution(String com.example.aop.util.*.get*())")
	public Object checkReturn(ProceedingJoinPoint joinPoint) throws Throwable {

		// aspect 가 적용된 메소드를 수행하고 리턴되는 데이터 받아오기 
		Object obj=joinPoint.proceed();
		
		//원래 type 으로 casting 해서 조사해 볼수가 있다.
		String a = (String)obj;

		//조사후 아예 다른 값을 리턴해 줄수도 있다. 
		//return obj;
		return "놀자 놀자";
	}	
  • get메소드가 호출 될때 놀자 놀자 를 리턴한다는 코드이다.

결과 👍

profile
새니의 뒤죽박죽 개발 일기📝

0개의 댓글