XML 기반으로 작성된 AOP 구현 방법에 대해서 소개하려고 한다.
AOP의 관점에 대한 5가지 방식을 모두 적용해보았다.
[태스트 환경]
* IDE: Eclipse 2020-06
* Spring Framework 4.2.4.RELEASE
* Aspectjweaver 1.6.10
* Spring-aop 4.2.4.RELEASE
* JUnit 5
1. 프로젝트 구성도
프로젝트 구성도이다.
그림 1, 그림 2. 프로젝트 구성도
2. 프로젝트 생성
Spring Legacy Project로 프로젝트를 생성한다.
참고로 Spring MVC Project로 선택하고 생성해야 한다.
3. Build Path, Java Compiler, Project Factes 버전 맞춰주기
* Build Path: JRE 버전을 1.8로 변경해준다.
- Add Library로 JUnit 5를 등록해준다.
* Java Compiler: Compiler compliance level - 1.8로 변경해준다.
* Project Factes: Java 버전을 1.8로 변경해준다.
4. POM.xml 설정하기
(중략)
<properties>
<java-version>1.8</java-version>
<org.springframework-version>4.2.4.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- AspectJWeaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Spring AOP 추가(Java) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework-version}</version>
</dependency>
5. applicationContext.xml (src/main/resources/applicationContext.xml)
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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- 방법1 - JAVA -->
<!-- JAVA 방식(어노테이션)의 AOP - AspectJ Weaver -->
<!-- <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 어노테이션 작업시 필수 선언해야 함. -->
<!-- XML 방식의 AOP - AsepectJ Weaver -->
<bean id="resultAOP" class="com.website.example.test.ResultAOP"></bean>
<bean id="txAdviceXML" class="com.website.example.aop.LogAdvisorXML"></bean>
<aop:config>
<!-- txAdviceXML 하나 영역임 -->
<aop:aspect ref='txAdviceXML'>
<!-- 진입영역 -->
<!-- 1개만 가능함 -->
<!-- <aop:pointcut id="point1" expression="execution(* com.website.example.test..*())"/> -->
<aop:pointcut id="point1" expression="execution(* com.website.example.test.ResultAOP..*())"/>
<!-- before -->
<aop:before method="beforeAdvice" pointcut-ref="point1"/>
<!-- after -->
<aop:after method="afterAdvice" pointcut-ref="point1"/>
<!-- around(메서드 자체를 가로채기) -->
<aop:around method="aroundAdvice" pointcut-ref="point1"/>
<!-- afterThrowing -->
<aop:after-throwing method="afterThrowing" pointcut-ref="point1"/>
<!-- afterReturning -->
<aop:after-returning method="afterReturning" pointcut-ref="point1"/>
</aop:aspect>
<!-- 2번째 선언자 -->
</aop:config>
</beans>
파일명: applicationContext.xml
[첨부(Attachments)]
6. ResultAOP.java - com.website.example.text
핵심 로직에 해당되는 부분이다. 이 부분을 비즈니스 로직이라고 표현하기도 한다.
package com.website.example.test;
public class ResultAOP {
public void method1() {
System.out.println("[중간]:");
// afterThrowing 유발 코드
// int d = 2/0;
System.out.println("결과: 메서드");
}
}
파일명: ResultAOP.java
[첨부(Attachments)]
7. LogAdvisor.java - com.website.example.aop
인터페이스 정의이다.
package com.website.example.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public interface LogAdvisor {
public void beforeAdvice();
public void afterAdvice();
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable;
public void afterThrowing();
public void afterReturning();
}
파일명: LogAdvisor.java
[첨부(Attachments)]
8. LogAdvisorXML.java - com.website.example.aop
package com.website.example.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class LogAdvisorXML implements LogAdvisor{
// around advice
@Override
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("2단계A?:");
System.out.println("aroundMethod 호출 1");
// 원래의 메소드를 호출한다.
Object obj = pjp.proceed();
System.out.println("2단계B?:");
System.out.println("aroundMethod 호출 2");
return obj;
}
// before advice
@Override
public void beforeAdvice() {
System.out.println("1단계:");
System.out.println("beforeMethod 호출");
}
// after
@Override
public void afterAdvice() {
System.out.println("5단계:");
System.out.println("afterMethod 호출");
}
// afterThrowing
@Override
public void afterThrowing() {
System.out.println("4단계:");
System.out.println("afterThrowing 호출");
}
// afterReturning
@Override
public void afterReturning() {
System.out.println("3단계:");
System.out.println("afterReturning 호출");
}
}
파일명: LogAdvisorXML.java
[첨부(Attachments)]
9. TestMain.java - com.website.example.unit
package com.website.example.unit;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.website.example.test.ResultAOP;
public class TestMain {
// 사용방법1
@Test
public void sample() {
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
ResultAOP rAOP = (ResultAOP) factory.getBean("resultAOP");
rAOP.method1();
factory.close();
}
// 사용방법2
@Test
public void sample2() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ResultAOP rAOP = ctx.getBean("resultAOP", ResultAOP.class);
//rAOP.method1();
ctx.close();
}
}
파일명: TestMain.java
[첨부(Attachments)]
10. 동작 결과
구현한 코드의 동작 결과이다.
그림 3. 출력 결과 1
그림 4. 출력 결과 2
11. 맺음글(Conclusion)
직관적으로 AOP를 아주 쉽게 이해할 수 있도록 작성하였다.