개발노트/Spring

[Spring] AOP(Aspect Oriented Programming)

Dahoon06 2021. 6. 17. 16:57
728x90
반응형

AOP => 관점 지향 프로그래밍

AOP의 핵심개념 : 관심분리(Separation of Concerns)

: 어떤 로직을 기준으로 핵심적인 관점, 부과적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화 하겠다는 것.

모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것

 

예로 핵심적인 관점은 우리가 적용하고자 하는 핵심 비즈니스 로직이 된다. 또한 부가적인 관점은 로직을 실행하기 위해서 행해지는 데이터베이스 연결 로깅, 파일 입출력등이 있다.

=> 횡단 관심(Cross Cutting Concerns)

** IoC가 결합도와 관련이 있다면, AOP는 응집도와 관련이 있다.

 

 

 

AOP사용

1. xml파일을 사용

2. 어노테이션을 사용

 

 

1) XML문서 사용

먼저 pom.xml에서 해당 dependency 확인 및 추가

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>${org.aspectj-version}</version>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.8.8</version>
</dependency>	

 

 

해당 라이브러리가 있는지 확인

 

 

설정파일로 설정한 xml파일로 가서 Namespace -> aop추가

xmlns:aop="http://www.springframework.org/schema/aop"

 

사용준비 끝


조인 포인트(Joinpoint)

: 클라이언트가 호출하는 모든 비즈니스 메소드 -> 포인트컷 대상, 포인트컷 후보

 

포인트컷(Pointcut)

: 특정 조건에 의해 필터링된 조인포인트, 수많은 조인포인트 중에 특정 메소드에서만 횡단 공통기능을 수행시키기 위해서 사용한다.

 

어드바이스(Advice)

: 횡단 관심에 해당하는 공통 기능의 코드, 독립된 클래스의 메소드로 작성

 

위빙(Weaving)

: 포인트컷으로 지정한 핵심 관심 메소드가 호출될 때, 어드바이스에 해당하는 횡단 관심 메소드가 삽입되는 과정을 의미한다.

이를 통해 비즈니스 메소드를 수정하지 않고도 횡단 관심에 해당하는 기능을 추가하거나 변경이 가능해진다.

 

애스팩트(Aspect)

: 포인트컷과 어드바이스의 결합이다. 어떤 포인트컷 메소드에 대해 어떤 어드바이스 메소드를 실행할지 결정한다.

 

 

예시)

<aop:config>
	<aop:pointcut expression="execution(* com.jdh.board..*Impl.*(..))" id="allPointcut"/>
	<aop:pointcut expression="execution(* com.jdh.board..*Impl.get*(..))" id="getPointcut"/>
	<!-- 실질적으로 값을 설정할때는 aspect 사용 -->
        <aop:aspect ref="log">
<!-- <aop:before method="printLogging" pointcut-ref="allPointcut"/>
     <aop:before method="printLogging" pointcut-ref="getPointcut"/> -->
		<aop:after method="printLogging" pointcut-ref="allPointcut"/> 어드바이스
	</aop:aspect>
    <aop:advisor >
    어드바이저는 주로 트랜젝션을 설정할때 사용된다.
    </aop:advisor >
</aop:config>

aop를 설정하기 위해서는 <aop:config> 태그 내부에 설정

 

포인트컷(PointCut)

: <aop:pointcut expression="execution( ~~~~~ )함수" id="유일한식식별값" />

 

expression 내부의 execution() 명시자 설정
ex). execution(* com.jdh.board..*Impl.*(..)
-> execution( 리턴값   패키지경로  클래스명  메서드명(..))

 

리턴 타입

표현식 설명
* 모든 리턴타입 허용
void 리턴타입이 void인 메서드 선택
!void 리턴타입이 void가 아닌 메서드 선택

패키지 지정

표현식 설명
com.jdh.domain 정확하게 com.jdh.domain 패키지만 선택
com.jdh.domain.. com.jdh.domain 패키지로 시작하는 모든 패키지 선택

메서드 지정

표현식 설명
*(..) 모든 메서드 선택
test*(..) test메서드 선택

 

매개변수 지정

표현식 설명
(..) 모든 매개변수
(*) 반드시 1개의 매개변수를 가지는 메소드만 선택
(com.jdh.domain.user.model.User) 매개변수로 User를 가지는 메소드만 선택. 꼭 풀패키지명이 있어야함
(!com.jdh.domain.user.model.User) 매개변수로 User를 가지지않는 메소드만 선택
(Integer, ..) 한 개 이상의 매개변수를 가지되, 첫 번째 매개변수의 타입이 Integer인 메소드만 선택
(Integer, *) 반드시 두 개의 매개변수를 가지되, 첫 번째 매개변수의 타입이 Integer인 메소드만 선택

 

메서드 동작 시점

동작 시점 설명
Before 메서드 실행 전에 동작
After 메서드 실행 후에 동작
After-returning 메서드가 정상적으로 실행된 후에 동작
After-throwing 예외가 발생한 후에 동작
Around 메서드 호출 이전, 이후, 예외발생 등 모든 시점에서 동작

 

 


XML -> 어노테이션 형식으로

 

<bean id="log" class="com.jdh.spring.common.LogAdvice" />
	<aop:config>
		<aop:pointcut expression="execution(* com.jdh.spring..*Impl.*(..))" id="allPointcut"/>
		<aop:pointcut expression="execution(* com.jdh.spring..*Impl.get*(..))" id="getPointcut"/>
		
		<aop:aspect ref="log">
			<aop:after method="printLog" pointcut-ref="getPointcut"/>
		</aop:aspect>
	</aop:config>
	
	<bean id="before" class="com.jdh.spring.common.BeforeAdvice" />
	<aop:config>
		<aop:pointcut expression="execution(* com.jdh.spring..*Impl.*(..))" id="allPointcut"/>
		
		<aop:aspect ref="before">
			<aop:before method="beforeLog" pointcut-ref="allPointcut"/>
		</aop:aspect>
	</aop:config>
	
	<bean id="after" class="com.jdh.spring.common.AfterReturningAdvice" />
	<aop:config>
		<aop:pointcut expression="execution(* com.jdh.spring..*Impl.*(..))" id="allPointcut"/>
		<aop:aspect ref="after">
			<aop:after-returning method="afterLog" pointcut-ref="allPointcut"/>
		</aop:aspect>
	</aop:config>
	
	<bean id="exeption" class="com.jdh.spring.common.AfterThrowingAdvice" />
	<aop:config>
		<aop:pointcut expression="execution(* com.jdh.spring..*Impl.*(..))" id="allPointcut"/>
		<aop:aspect ref="exeption">
			<aop:after-throwing method="exceptionLog" pointcut-ref="allPointcut"/>
		</aop:aspect>
	</aop:config>
	
	<bean id="around" class="com.jdh.spring.common.AroundAdvice" />
	<aop:config>
		<aop:pointcut expression="execution(* com.jdh.spring..*Impl.*(..))" id="allPointcut"/>
		<aop:aspect ref="around">
			<aop:around method="aroungLog" pointcut-ref="allPointcut"/>
		</aop:aspect>
	</aop:config>

예제에서 사용됐던 xml형식의 AOP

각각의 특징에 맞게 xml에 등록시켜 사용했다. 하지만 어노테이션 형식으로 바뀌게 되면 필요없는 코드이다.

xml파일에서 기존의 AOP관련 코드를 지우고 새로운 코드 추가

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

스프링 컨테이너에서 AOP관련 어노테이션을 인식하고 용도에 맞게 처리해준다. 

 

** AOP는 스프링 컨테이너가 처리하게 하려면 반드시 <bean>등록을 하거나 @Service 사용하여 컴포넌트가 검색될 수 있도록 해야한다.!!

 

<aop:pointcut ~~~> => @Pointcut으로 변경

** 이때 @Pointcut 참조 하기 위해서는 메서드을 통하여 식별한다.

참조 메서드는 반드시 비어있는 형태의 메서드!! 

ex)
@Pointcut("execution(* com.jdh.spring..*Impl.*(..)")
	public void allPointcut() { }
	
@Pointcut("execution(* com.jdh.spring..*Impl.get*(..)")
	public void getPointcut() { }

 

어드바이스 설정

@Service
public class LogAdvice {
	
	@Pointcut("execution(* com.jdh.spring..*Impl.*(..)")
	public void allPointcut() { }
	
	@Pointcut("execution(* com.jdh.spring..*Impl.get*(..)")
	public void getPointcut() { }
	
	@Before("allPointcut()")  // 포인트컷 참조 메서드 지정
	public void printLog(JoinPoint jp){
		System.out.println("[공통 로그] : 비즈니스 수행전 동작(LogAdvice)");
	}
}
어노테이션 설명
@Before 비즈니스 메서드 실행 전 동작
@AfterReturning 비즈니스 메서드가 성공적으로 리턴되면 동작
@AfterThrowing 비즈니스 메서드 실행 중 예외가 발생하면 동작
@After 비즈니스 메서드가 실행된 후, 무조건 실행
@Arount 호출 자체를 가로채 비즈니스 메서드 실행 전후에 처리할 
로직을 삽입 할 수 있다.

@Aspect

: 포인트 컷과 어드바이스의 결합

@Service
@Aspect 
public class LogAdvice {
	
	@Pointcut("execution(* com.jdh.spring..*Impl.*(..)")
	public void allPointcut() { }   // 포인트컷
    									+
	@Before("allPointcut()")        //어드바이스
	public void printLog(JoinPoint jp){
		System.out.println("[공통 로그] : 비즈니스 수행전 동작(LogAdvice)");
	}
}

설정된 어노테이션에 의해 위빙(weaving)처리 된다.

 

728x90
반응형

'개발노트 > Spring' 카테고리의 다른 글

[Spring] JDBC  (0) 2021.06.18
[Spring] IoC(inversion of Control)  (0) 2021.06.18
[Spring] src/main/resources 구조  (0) 2021.06.15
[Spring] lombok.jar 설정  (0) 2021.06.14
[Spring] 입문  (0) 2021.06.09