핵심 관심 사항: BankingService, AccountService, CustomerService
공통 관심 사항: Security, Transaction, Other
Target: 핵심기능을 담고 있는 모듈로 target은 부가기능을 부여할 대상이 됨
Advice: 어느 시점에 어떤 공통 관심 기능(Aspect)을 적용할지 정의한 것. Target에 제공할 부가기능을 담고 있는 모듈
POJO class를 이용한 AOP 구현
Spring API를 이용한 AOP 구현
Annotation을 이용한 AOP 구현
XML Schema 확장 기법을 통해 설정 파일을 작성
POJO기반 Advice Class 작성
pointcut: 직접 pointcut을 설정. 호출 할 method의 패전 지정
pointcut-ref: <aop:aspect> 태그의 id명을 넣어 pointcut 지정
method: Aspect Bean에서 호출할 method명 지정
빈 객체를 사용하는 코드에서 스프링이 생성한 AOP 프록시의 메소드를 호출
AOP 프록시는 <aop:before>에서 지정한 메소드를 호출
AOP 프록시는 Aspect 기능 실행 후 실제 빈 객체의 메소드를 호출
대상 객체의 method 실행이 정상적으로 끝난 뒤 실행 됨
return type: void
argument:
빈 객체를 사용하는 코드에서 스프링이 생성한 AOP 프록시의 메소드를 호출
AOP 프록시는 실제 빈 객체의 메소드를 호출 (정상 실행)
AOP 프록시는 .<aop:after-returning>에서 지정한 메소드를 호출
대상 객체의 method 실행 중 예외가 발생한 경우 실행 됨
return type: void
argument:
없거나 JoinPoint 객체를 받는다. JoinPoint는 항상 첫 argument로 사용
대상 method에서 전달되는 예외 객체를 argument로 받을 수 있다
빈 객체를 사용하는 코드에서 스프링이 생성한 AOP 프록시 메소드를 호출
AOP 프록시는 실제 빈 객체의 메소드를 호출(exception 발생)
AOP 프록시는 .<aop:after-throwing>에서 지정한 메소드를 호출
대상 객체의 method가 정상적으로 실행 되었는지 아니면 exception을 발생시켰는지의 여부와 상관없이 메소드 실행 종료 후 공통 기능 적용
return type: void
argument
빈 객체를 사용하는 코드에서 스프링이 생성한 AOP 프록시 메소드를 호출
AOP 프록시는 실제 빈 객체의 메소드를 호출(정상 실행, exception 발생: java의 finally와 같음)
AOP 프록시는 .<aop:after>에서 지정한 메소드를 호출
위의 네 가지 Advice를 다 구현 할 수 있는 Advice
return type: Object
argument:
빈 객체를 사용하는 코드에서 스프링이 생성한 AOP 프록시 메소드를 호출
AOP 프록시는 <aop:around>에서 지정한 메소드를 호출
AOP 프록시는 실제 빈 객체의 메소드를 호출
AOP 프록시는 <aop:around>에서 지정한 메소드를 호출
대상 객체에 대한 정보를 가지고 있는 객체로 Spring Container로 부터 받는다
org.aspectj.lang 패키지에 있다
반드시 Aspect method의 첫 argument로 와야한다
주요 method
applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!--annotation 을 이용 직접 Aspect Class에 Advice 및 Pointcut 설정-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<!--Aspect를 사용하기 위한 객체 -->
<bean class="UserAspect" id="userAspect"></bean>
<!-- Main에서 사용할 객체들 생성 -->
<bean class="GeneralUser" id="generalUser"></bean>
<bean class="AdminUser" id="adminUser"></bean>
<!--annotation을 안 쓴다면 이렇게 구현해줘야 한다 -->
<!-- <aop:config>
<aop:pointcut expression="execution(* *())" id="mypt"/>
<aop:aspect ref="userAspect">
<aop:before method="before" pointcut-ref="mypt"/>
<aop:after-returning method="afterReturn" pointcut-ref="mypt"/>
<aop:after-throwing method="afterThrow" pointcut-ref="mypt"/>
<aop:after method="after" pointcut-ref="mypt"/>
</aop:aspect>
</aop:config> -->
</beans>
AopTest.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AopTest {
public static void main(String[] args) {
ApplicationContext factory = new ClassPathXmlApplicationContext("applicationContext.xml");
GeneralUser guser = factory.getBean("generalUser", GeneralUser.class);
AdminUser auser = factory.getBean("adminUser", AdminUser.class);
//테스트 코드 작성
System.out.println("***********1. GeneralUser");
guser.useApp();
System.out.println("***********2. AdminUser");
try {
auser.useApp();
} catch(Exception e) {
}
((ClassPathXmlApplicationContext)factory).close();
}
}
UserAspect.java
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//@Aspect 어노테이션을 적용한 클래스는 PointCut과 Advice 설정 그리고 Aspect 구현을 함께 제공
@Aspect
public class UserAspect {
//<aop:aspectj-autoproxy proxy-target-class="true"> tag ->직접 구현
//* *() -> 모든 반환형 & 모든 함수 이름에 대해서 실행한다
@Before("execution(* *())")
public void before() {
System.out.println("애플리케이션을 시작합니다.");
}
//pointcut (공통 관심 사항이 적용될 JoinPoint)
@AfterReturning(pointcut="execution(* *())", returning="ret")
public void afterReturn() {
System.out.println("애플리케이션의 사용을 끝냅니다.");
}
//pointcut (공통 관심 사항이 적용될 JoinPoint)
@AfterThrowing(pointcut="execution(* *())", throwing="e")
public void afterThrow() throws Throwable {
System.out.println("애플리케이션에 문제가 생겨 점검합니다.");
}
@After("execution(* *())")
public void after() {
System.out.println("애플리케이션을 상태와 관련없이 종료합니다.");
}
}
User.java
public interface User {
void useApp() throws ApplicationException;
}
GeneralUser.java
public class GeneralUser implements User{
@Override
public void useApp() {
System.out.println("애플리케이션을 사용합니다.");
}
}
AdminUser.java
import java.util.Random;
public class AdminUser implements User {
@Override
public void useApp() throws ApplicationException {
System.out.println("애플리케이션을 관리합니다.");
// 예외 발생 코드
Random random = new Random();
if(random.nextInt(2) == 1) {
throw new ApplicationException();
}
}
}
ApplicationException.java
public class ApplicationException extends Exception {
public ApplicationException() {
this.printStackTrace();
}
}