AOP Spring day 66 Around Advice

stan·2023년 8월 10일
0

Spring

목록 보기
9/22

AOP : Aspect Oriented Programming
관점 지향 프로그래밍
는 응집도를 높일 수 있는 구조를 의미함

IoC로 결합도를 낮췄으니 AOP로 응집도를 높임

현재 ctrl 구조

1) 로그를 찍음
2) 권한확인 단계(안보이는데) 하려고 하는 메서드의 보안, 인증, 외부 API 허가가 나왔는지
인가확인
3) 확인이 되면 비즈니스 메서드를 함
4) (안보이지만) 관제로그를 찍을 수 있음
디지털포렌직 : 데이터 삭제할지 뜨문뜨문 지워짐
그것들을 찾아서 다시 살리는
디지털포렌직이 가능한 이유는 컴퓨터가 무슨 행동을 하면 무조건 기록에 남기도록 되어있음

[기존의 Controller 메서드를 예시로 설명 : ]
1) (개발자용) 로그
2) 권한 확인 : 보안, 인증, 호가, ...
3) 비즈니스 메서드 [CRUD, 핵심로직, 핵심관심]
4) 트랜잭션, 보안 관제 록,, ... 수행의 마무리 단계

ctrl에 로그인이 1,2,3,4 수능로 진행 됨
3 : selectOne()

ctrl에서 signUp.do
사용자의 요청이 달라졌는데 정말 달라지는건 3번밖에 없음 R대신 C로 (insert())
1,2,4번은 계속 사용됨

1,2,4번은 매번 반복되기 때문에 모듈화
"관심 분리(Separation of Concerns)"
Concern : 핵신 관심 : 로직
== 로직분리
1,2,4 : 공통 로직, 횡단 관심 (반복되는 로직들은 어딜가도 실행되기 때문에)
3 : 핵심 관심, 핵심로직, 비즈니스 메서드, CRUD

횡단 관심


[실습을 로그로]
1) AOP는 라이브러리가 필요함! -> pom.xml에 추가
AOP라이브러리는 pom.xml에 추가
dependencies안에 넣어야 함
dependency 2개 추가
하나는 Aspect J version
하나는 Aspect j weaver

2) applicationContext.xml에 AOP 네임스페이스 추가
-> 왜 applicationContext에 추가 하나요?
: AOP가 관심분리를 controller내부에서 진행 하고 있기 때문에
<context:component-scan...>과 소통 할 확률이 높음
AOP설정 완료되는 시점이 사용자가 (브라우저가,클라이언트가) *.do를 하는 시점보다
더 먼저여야 하기 때문

확인 : Maven Dependencies에 Jar 2개추가 되어야 함

모든 C가 자유롭게 부를 수 있어야 하기 때문에 com.spring.biz.commom에 만들기

logAdvice.printLog();를 C에 넣으면
로그와 CRUD수행 사이에 다른로그들이 들어갈 수 있기 때문에
이미 조합이 완료된 서비스를 가져와서 사용되는것을 좋아함
즉 조합을 Service레이어에서

logAdvice버전이 새로 나왔다고 치면 :
기존 로그보다 이쁘게 만들라는 오더를 받음
==>> LogAdvice2.java
메서드이름 printLog2

그러면 Service 레이어에서 멤버변수와 메서드를 모두 다시 바꾸어야 함

일반클래스로 했기때문에 실제 적용이 된건 아님
advice를 업데이트 할때 일일히 다 코드를 적어가면서 업데이트하는건 좋지 않음

  • applicationContext에 먼저 LogAdvice new 하기

  • LogAdvice new 를 직접 하는건 결합도가 높아짐 (안좋음)
    java에 직접 적은 로그 부분들 모두 설정으로

<aop:pointcut expression="execution(OUTPUT FUNCNAME(INPUT))" id=""/>
expression 내부에는 메서드 시그니쳐 작성
어쩌구어쩌구 Impl로 끝나는애 한테 결합할 예정
<aop:pointcut expression="execution( com.spring.biz..Impl.(..))" id=""/>
== output은 무엇이 와도 상관없다 (boolean,list,void...) output은1개로 정대져 있으니

== input은 1개이상일 수 있으니 ..
== com.spring.biz..Impl.의 모든 메서드

	<bean id="logAdvice" class="com.spring.biz.common.LogAdvice"/>
-> new를 컨테이너가 대신 수행
	<aop:config> <!-- aop설정할거야 -->
-> 찐 AOP 설정
		<aop:pointcut expression="execution(* com.spring.biz..*Impl.*(..))" id="aPointcut"/>
		-> 핵심 로직(CRUD)
		<!-- 결합 -->
		<aop:aspect ref="logAdvice">
		-> logAdvice랑 "결합"시켜줘!
			<aop:before method="printLog" pointcut-ref="aPointcut"/>
			-> 언제? aPointcut 수행"전에" pringLog메서드 호출해줘!
		</aop:aspect>
	</aop:config>	

xml을 들여다보지 않으면 AOP가 걸려있는줄 알수 없음
- java파일을 열면 자바만 보임 (보기좋음)
- 설정을 알려면 xml을 들여다 봐야 함

※AOP 용어정리

1) Advice : 횡단관심, 공통로직

1번 (개발자용)로그를 Advice로 빼낸것임: 1번은 비즈니스 메서드보다 먼저 수행 되는데
4번은 비즈니스보다 나중에 수행됨

  • 그래서 모든 advice는 동작시점을 설정할 수 있음
  • 비즈니스 메서드를 기준으로 전/후/함께/항상 할지 ....

2) pointcut 포인트컷
핵심 로직, 핵심 관심, 비즈니스 메서드, CRUD
공통 로직인 Advice가 결합될 대상을 의미함

<aop:pointcut expression="execution(OUTPUT FUNCNAME(INPUT))" id=""/>
expression 내부에는 메서드 시그니쳐 작성
어쩌구어쩌구 Impl로 끝나는애 한테 결합할 예정
<aop:pointcut expression="execution(* com.spring.biz..*Impl.*(..))" id=""/>
	== output은 무엇이 와도 상관없다 (boolean,list,void...) output은1개로 정대져 있으니 *
	== input은 1개이상일 수 있으니 .. 
	== com.spring.biz..*Impl.*의 모든 메서드

3) Aspect 애스팩트(Advisor 어드바이져)
포인트컷 + 어드바이스
포인트컷과 어드바이스의 "결합" 그 자체를 의미함
애스팩트 설정에 따라 위빙이 처리됨

4) Weaving 위빙
포인트컷으로 지정한 핵심 관심 메서드가 호출될때,
어드바이스에 대항하는 횡단 관심 메서드가 삽입되는 과정 그 자체를 의미함
스프링은 런타임 위빙 방식을 사용함
(런타임 : 실행을 하면 결합이 된다)

5) JoinPoint 조인포인트
포인트컷 후보
포인트컷이 될수있는 대상들
핵심관심들...


내가 로그어드바이스가 있었는데 b포인트컷이랑 애스팩트를 했는데 위빙이 안되 ㅜㅠ
== 로그를 찍는 기능의 횡단관심이 있었는데
이름이 bPointcut인 CRUD랑 결합 설정을 했는데 실행을 시켜도 결합이 안되
==> 설정(applicationContext.xml)에 오타있겠지뭐..
bean이 안되어있지 않을까,,, 메모리에 쓸 객체가 적재(loading)가 안되어있는거아닐까...


aPointcut은 Impl로 끝나는 모든 메서드에 대해
bPointcut은 Impl.select로 시작하는 메서드에 대해서만 해 달라고 설정

포인트컷을 여러개 등록할수 있음
CUD는 DB에 변화를 줄 수 있음
데이터에 대한 확실한 검증이 필요함
상대적으로 보안, 유효성 검사, 트랜잭션,...등이 많이 필요함

하지만 R는(보기만하면되는거) DB에 변화가 없음
보려는 데이터에 접근할수있는 권한이 있는지
상대적으로 공통로직이 적게 필요함

글작성 페이지로 이동만 할때에는 service를 사용하지 않기때문에 아무일도 일어나지 않음

일부 포인트것에만 어드바이스(공통로직,횡단관심)가 동작할수있도록 설정가능

aop:
after-returning은 아웃풋이 있을떄 그 이후
after-throwing은 예외가 발생하면 그 이후 (예외발생안하면 동작안함)
after-around 좀 특이한 애

after 비즈니스 메서드 후에 어드바이스가 호출됨
after-returning 비즈니스메서드 output반환후에 어드바이스가 호춯됨
after-throwing 비즈니스 메서드 오류발생후 어드바이드가 호출됨
around <<< 실습
before 비즈니스 메서드 전에 어드바이스가 호출됨

around는 동작시점이 비즈니스 메서드를 수행하기 전,후에 호출됨
조심 : !비즈니스 메서드 전에 1번, 수행하기 후에 1번 하는것이 아님!
around가 진행되는 동안에 비즈니스 메서드가 내부에서 호출되는 것임

하나의 묶음으로 봐야 할때 around 사용

로그: 전
외부 메서드 데려다 호출
로그: 후
이렇게 한번의 흐름을 필요로 하면 around를 쓰면 됨


AroundAdvice 특별한 애

<context:component-scan base-package="com.spring.biz" />

	<bean id="aroundAdvice" class="com.spring.biz.common.AroundAdvice" />
	<bean id="returningAdvice" class="com.spring.biz.common.ReturningAdvice"/>
	
	<aop:config>
		<aop:pointcut expression="execution(* com.spring.biz..*Impl.*(..))" id="aPointcut" />
		<aop:pointcut expression="execution(* com.spring.biz..*Impl.select*(..))" id="bPointcut" />
      
<aop:aspect ref="aroundAdvice">
			<aop:around method="aroundPrintLog" pointcut-ref="bPointcut" />
		</aop:aspect>
	</aop:config>
  • <bean id="aroundAdvice" class="com.spring.biz.common.AroundAdvice" />
    // class="com.spring.biz.common.AroundAdvice" 여기에 있는 클래스를 bean에 등록
    // 그럼 new해서 인스턴스생성 (applicationContext.xml(루트컨테이너)이 그 주체)

  • <aop:config> //AOP의 pointcut(핵심로직) a랑b 두개 설정해둠
    <aop:pointcut expression="execution( com.spring.biz..Impl.*(..))" id="aPointcut" />
    //com.spring.biz.로 시작하는 패키지안에서 Implement를 하고 있는 모든 클래스의 모든 메서드를 A포인트컷으로 설정

  • <aop:pointcut expression="execution( com.spring.biz..Impl.select*(..))" id="bPointcut" />
    //com.spring.biz.로 시작하는 패키지안에서 Implement를 하고 있는 모든 클래스의 메서드들중에 select로 시작하는 메서드들을 B포인트컷으로 설정

  • <aop:aspect ref="aroundAdvice"> //aroundAdvice라는 위의 bean태그(new해주는컨테이너)를 참조
    //그러면 AdroundAdvice라는 java클래스를 참조하게됨
    <aop:around method="aroundPrintLog" pointcut-ref="bPointcut" />
    //AOP 관점 정의: bPointcut에서 설정한 메서드들 (select로 시작하는)이 동작할때
    //AroundAdvice클래스 안에있는
    //aroundPrintLog 메서드를 수행
    </aop:aspect>


AroundAdvice

package com.spring.biz.common;

import org.aspectj.lang.ProceedingJoinPoint;

public class AroundAdvice {// around는 인자로 pjp를 반드시 가져야만함
	public Object aroundPrintLog(ProceedingJoinPoint pjp) throws Throwable {//인자로 가져야만함
		System.out.println("around 로그 전");
		
		Object obj = pjp.proceed(); //pjp를 내부에서 진행해주세요; 오류가 날 수도 있음: 예외처리
						//또한 외부의 비즈니스메서드가 selectOne 혹은 selectAll일수있음 : 아웃풋이 일수 있음 == Object로 받고 반환
		////여기쯤 내부에서 외부의 비즈니스메서드를 호출함
		
		System.out.println("around 로그 후");
		
		return obj;
	}
}
  • ProceedingJoinPoint 인터페이스는 Spring AOP 시스템에 의해 자동으로 주입
    - 아까 pom.xml에 dependency 추가 하고 applicationContext.xml에 namespace 추가 했음
    - Maven Dependencies 라이브러리에 .jar파일 두개 추가 되었음

  • proceed(); 가 외부 메서드를 가져옴

※ around는 동작시점이 비즈니스 메서드를 수행하기 전,후에 호출됨

조심 : !비즈니스 메서드 전에 1번, 수행하기 후에 1번 하는것이 아님!
around가 진행되는 동안에 비즈니스 메서드가 내부에서 호출되는 것임

profile
이진 입니다

0개의 댓글