[ AOP 란? ]
" AOP란 OOP를 더 OOP 답게!"
: Aspect Oriented Programming = 관점 지향 프로그래밍
> AOP 적용 전
> AOP 적용 후
*위빙 : 횡단 관심 사항을 엮어준다.
* Aspect : 관점 !
시스템을 두 가지 관점으로 나누어 본다.
시스템을 핵심관심사(Core Concern) 와 횡단관심사(Cross-cutting Concern)로 구분하여 설계와 구현을 한다
- 핵심관심사(Core Concern)란 시스템의 목적에 해당하는 주요 로직 부분을 말한다
- 횡단관심사(Cross-cutting Concern)란 시스템의 여러 부분에 걸쳐 공통적이고 반복적으로 필요로 하는 처리내용을 말한다
- AOP는 시스템의 여러 영역에 걸쳐 공통적이고 반복적으로 적용된 횡단관심사(Cross-Cutting Concern)를 분리하여,
별도의 모듈에서 설계, 구현,운영하는 프로그래밍 기법이다 - 대표적인 횡단관심사는 로깅, 보안, 트랙잭션 관리, 예외 처리등이 있다
장점
: AOP를 적용하면,
핵심관심사항 서비스를 제외한 횡단관심사항 서비스를 별도의 모듈에서 개발하여 적용하므로,
여러 서비스에 걸쳐있는 반복적 작업을 줄일 수 있어 생산성이 높아진다.
이후 요구사항 변경 시에도 유연하게 대처할 수 있으므로, 유지보수성이 높아진다.
사용 방법 - aop-ioc.xml
1. 횡단 관심 사항을 정의
2. IOC 기반 하에, AOP 설정을 pointcut으로 적용대상을 지정
3. advice로 횡단괌심사항 서비스 적용 시점을 지정한다.
[ AOP 사용 환경 설정 ]
> pom.xml에 라이브러리 추가
<!-- AOP Library -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.1</version>
</dependency>
> Spring AOP Pointcut AspectJ 표현식 (XML 기반)
executeion([returnType] [package].[className].[methodName] ([매개변수리스트] ))
execution( * com.exam.*Service.find*(..))
: com.exam 하위의 Serivce로 마치는 클래스의 리턴타입 유형에 관계없이,
find 로 시작하는 메서드명을 가진 매개변수 0~* 인 메서드를 AOP 적용대상으로 한다
[ 사용 예 ]
- execution(String com.exam.service..*.search*(..))
com.exam.service 패키지 또는 그 하위 패키지의 모든 클래스 중 String 리턴타입인 search 이름으로 시작하는 모든 메서드를 적용대상으로 한다 - within(com.exam.service.*)
com.exam.service 패키지 하위의 모든 클래스의 모든 메서드를 대상으로 한다 - bean(*Service)
IOC 컨테이너에 관리되는 bean이름이 Service로 끝나는 bean의 모든 메서드를 대상으로 한다
[ AOP 주요 용어 ]
Aspect | AOP의 단위가 되는 횡단관심사를 의미 ex) 로깅,트랜잭션관리 등 |
JoinPoint | 횡단관심사가 실행될 지점 |
Advice | 횡단관심사를 처리하는 부분, 특정 JoinPoint에서 실행되는 코드로서 before, after returing , after throwing, after , around advice가 있다 |
Pointcut | 여러 JoinPoint 중 실제 어드바이스를 적용할 곳을 선별하기 위한 표현식 |
Weaving | 애플리케이션의 적절한 지점에 aspect를 적용하는 것을 말함 |
Target | Aspect 가 적용된 객체를 말한다 |
[ AOP Advice 유형 ]
- Before : 메서드 실행 전에 실행하는 Advice
- After Returning : 메서드 정상 실행 후 실행하는 Advice
- After Throwing : 메서드 실행시 예외 발생시 실행하는 Advice
- After : 메서드 정상 실행 또는 예외 발생 상관없이 실행하는 Advice
- Around : 위 네가지 Advice를 모두 포함 , 모든 시점에서 실행할 수 있는 Advice
[ AOP 주요 디자인 패턴 ]
> Proxy(프록시) Design Pattern
- AOP 적용 시에는 동일한 인터페이스를 implements 하는 Proxy 객체가 반환된다 (Delegate : 대리한다)
- ex)
<<interface>>Subject = <<interface>> BoardSerivce
RealSubject = BoardServiceImpl
Spring AOP Proccess
[ 적용 예제 ]
기존 시스템은 MemberService의 다수 메서드와 BoardService의 다시 메서드가 실행 중인 상태
-> 요구사항 : 각 서비스의 메서드에서 수행완료 시간을 특정 파일에 기록하도록 추가 요구사항이 들어왔다.
1) AOP 적용 X : 각 서비스 클래스의 모든 메서드 각각에, 공통된 작업을 직접 코딩을 하여 추가해야 한다.
2) AOP 적용 O
: 시스템을 '핵심 관심사항'과 '횡단 관심사항'으로 구분하여,
공통된 작업(추가요구사항)은 별도의 모듈에서 기능을 정의한 후,
대상과 시점을 지정하여 생산성있게 개발할 수 있다.
/BoardService.java <<interface>>
package model;
public interface BoardService {
public void registerInfo(String info);
public void getContentByNo(String no);
public void deletePostByNo(String no);
}
/BoardServiceImpl.java
- core 핵심 사항 : registerInfo / getContentByNo / deletePostByNo
- 그 외 많은 메서드있다고 가정
package model;
public class BoardServiceImpl implements BoardService {
@Override
public void registerInfo(String info) {
// core 핵심 관심 사항
System.out.println("BoardService registerInfo: "+ info);
}
@Override
public void getContentByNo(String no) {
// core 핵심 관심 사항
System.out.println("BoardService getContentByNo: "+ no);
}
@Override
public void deletePostByNo(String no) {
// core 핵심 관심 사항
System.out.println("BoardService deletePostByNo: "+ no);
}
// 그 외 많은 메서드가 있다고 가정..
}
/MemberService.java <<interface>>
package model;
public interface MemberService {
//interface는 접근제어가의 default가 public이다.
public void updateMember();
public void deleteMember();
public void getAllMember();
}
/MemberServiceImpl.java
- core 핵심 사항 : updateMember / deleteMember / getAllMember
- 그 외 많은 메서드있다고 가정
package model;
public class MemberServiceImpl implements MemberService {
@Override
public void updateMember() {
//core 핵심 관심 사항
System.out.println("MemberService updateMember");
}
@Override
public void deleteMember() {
//core 핵심 관심 사항
System.out.println("MemberService deleteMember");
}
@Override
public void getAllMember() {
//core 핵심 관심 사항
System.out.println("MemberService getAllMember");
}
// 그 외 많은 메서드가 있다고 가정..
}
횡단 관심 사항을 정의하는 클래스 - AOP 적용!
(Logging : 대상 메서드가 실행완료 후, 시간 정보를 특정 공간에 기록하는 서비스)
/CommonLoggingService.java
package aop.common;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.JoinPoint;
/*
* 횡단 관심사항을 정의한 클래스
*/
public class LoggingService {
//Log4j를 사용하기 위한 선언부
Logger log = LogManager.getLogger(LoggingService.class);
public void beforeLogging(JoinPoint point) {
//횡단 관심 사항을 적용할 대상 class의 이름
String className = point.getTarget().getClass().getName();
//횡단 관심 사항을 적용할 대상 메서드의 이름
String methodName = point.getSignature().getName();
//System.out.println(className+" "+methodName);
log.info(className + " "+ methodName);
}
}
횡단 관심 사항 서비스 정의한 bean + AOP 적용
1. 횡단 관심 사항을 정의
2. IOC 기반 하에, AOP 설정을 pointcut으로 적용대상을 지정
3. advice로 횡단괌심사항 서비스 적용 시점을 지정한다.
/ioc-aop.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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="boardService" class="model.BoardServiceImpl"></bean>
<bean id="memberService" class="model.MemberServiceImpl"></bean>
<!-- 횡단 관심 사항 서비스를 정의한 bean -->
<bean id="commonLogging" class="aop.common.CommonLoggingService"></bean>
<!-- AOP 설정 -->
<aop:config>
<!-- 1. 횡단관심사항을 정의한 bean -->
<aop:aspect ref="commonLogging">
<!-- 2. pointcut : 횡단 관심사항 적용 대상을 지정
<aop:pointcut expression="execution([접근제어자] [returnType] [package].[className].[methodName].([number])" id="[id]"/> -->
<aop:pointcut expression="execution(public * model.*Service.*(..))" id="pt"/>
<!-- 3. Advice : 횡단관심사항 서비스가 어느 시점에 적용될 것인가 지정
- after : 메서드 실행 완료 후 지정됨( 정상 실행 또는 예외 발생 상관X)
<aop:after method="[횡단관심사항bean id]" pointcut-ref="[pointcut id]"/>
-->
<aop:after method="timeLogging" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
/testController.java
package test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import model.BoardService;
import model.MemberService;
public class TestController {
public static void main(String[] args) {
ClassPathXmlApplicationContext factory
= new ClassPathXmlApplicationContext("ioc-aop.xml");
//boardSerivce 받아보기
BoardService bs = (BoardService) factory.getBean("boardService");
bs.deletePostByNo("1");
bs.getContentByNo("1");
bs.registerInfo("milk");
System.out.println("-------------------------");
//memberService 받아보기
MemberService ms = (MemberService) factory.getBean("memberService");
ms.deleteMember();
ms.getAllMember();
ms.updateMember();
factory.close();
}
}
[ 결과 ]
'Java Web Programming > 6. Spring | MyBatis' 카테고리의 다른 글
[Spring] 스프링 AOP의 Around Advice이용하기 + Log4j 활용 (2) | 2020.10.29 |
---|---|
[Spring] Logging 로깅 - Log4j (스프링 AOP 방식 적용) (0) | 2020.10.28 |
[Spring] DBCP를 Spring config로 설정해보기! (+IOC/DI+DL) (0) | 2020.10.27 |
[Spring] 비즈니스 로직 계층 추가 (IOC, DI+DL) (0) | 2020.10.27 |
[Spring] 생성자를 통한 DI/DL 적용(constructor-arg) + IOC + maven (0) | 2020.10.27 |