AOP란?
- Spring에서 처음 등장한 새로운 기술
- 공통의 관심사항을 적용해서 발생하는 의존관계의 복잡성과 코드 중복을 해소해 주는 프로그래밍 기법
AOP(Aspect Oriented Programming : 관점지향프로그래밍)
OOP(Object Oriented Programming :객체지향프로그래밍)
AOP 예제
프로젝트명: SpringAOP / 패키지명 : com.exe.aop
1. lib 받기 (maven)
- AOP 사용하려면 총 4개의 library 필요 - spring aop, AspectJ Runtime 1.8.13 , AspectJ Weaver 1.8.13, CGLib 3.2.5
2. Target 객체 생성
TargetA 클래스
package com.exe.aop;
import org.springframework.stereotype.Component;
@Component("targetA")// targetA란 이름으로 객체생성
public class TargetA {
public void doSomething1() {
System.out.println("TargetA.doSomething1");
}
public void doSomething2() {
System.out.println("TargetA.doSomething2");
}
public void doAnother1() {
System.out.println("TargetA.doAnother1");
}
public void doAnother2() {
System.out.println("TargetA.doAnother2");
}
}
TargetB 클래스
package com.exe.aop;
import org.springframework.stereotype.Component;
@Component("targetB")
public class TargetB {
public void doSomething1() {
System.out.println("TargetB.doSomething1");
}
public void doSomething2() {
System.out.println("TargetB.doSomething2");
}
public void doAnother1() {
System.out.println("TargetB.doAnother1");
}
public void doAnother2() {
System.out.println("TargetB.doAnother2");
}
}
- 이 메소드들에 Advice를 적용하면 Target 이 되는 것
3. app-context.xml 세팅
execution ( public void com..aop . * . *(..))
execution (메소드의 접근지정자 반환값 패키지명 . 클래스 . 메소드명(매개변수))
-> 어떠한 패키지, 어떠한 메소드든지 상관 없다
..은 생략이란 의미
* String 반환값만 받고 싶은 경우 : public String ~
* 특정 클래스의 특정 메소드만 하고 싶은 경우 : com..aop 부분만 건들면 됨
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- aop 관련된 것 상단에 추가 -->
<description>Example configuration to get you started.</description>
<context:component-scan base-package="com.exe.aop" />
<!-- execution(메소드 접근지정자,반환값,패키지명.클래스.메소드명(매개변수)) -->
<bean id="beforeAdvice" class="com.exe.aop.MyBeforeAdvice"/>
<aop:config>
<aop:aspect ref="beforeAdvice">
<aop:pointcut id="beforePointcut" expression="execution(public void com..aop.*.*(..))"/>
<aop:before method="beforeMethodCall" pointcut-ref="beforePointcut"/>
</aop:aspect>
</aop:config>
</beans>
beforeMethodCall은 내가 할 작업 즉, 공통으로 적용될 작업을 뜻한다.
그것을 beforePointcut에 넣어둔다
<aop:before : 어디에 걸건지 위치를 정한것 - ex) 메소드 앞에? 뒤에?
before을 썼다는건 메소드가 실행되기 전에 내가 지정한 작업을 실행하도록 설정한 것
실행되는 어드바이스의 메소드는 beforeMethodCall 이다
[Joinpoint]
애플리케이션 실행의 특정 지점을 의미
AOP에서 Aspect(횡단 관심사)를 적용하는 위치를 표시하는데 사용 (위치: 클래스안의 메소드를 뜻함)
[Pointcut]
여러 조인포인트의 집합. 언제 어드바이스를 실행하는 지 위치 표시
4. MAIN 절
package com.exe.aop;
import org.springframework.context.support.GenericXmlApplicationContext;
public class AopMain {
public static void main(String[] args) {
GenericXmlApplicationContext context =
new GenericXmlApplicationContext("app-context.xml");
TargetA ta = (TargetA)context.getBean("targetA");
// 4개의 메소드가 실행되기 전에 내가 지정한 작업이 출력되는 것
ta.doAnother1();
ta.doAnother2();
ta.doSomething1();
ta.doSomething2();
}
}
실행결과
Pointcut 종류에 따른 결과 보기
<>aop:after 이용 - Target 객체 실행 후 작동
MyAfterAdvice.java
@Component
public class MyAfterAdvice {
public void afterMethodCall() {
System.out.println("메소드 실행 후 (after)");
}
}
app-context.xml
<bean id="afterAdvice" class="com.exe.aop.MyAfterAdvice"/>
<aop:config>
<aop:aspect ref="afterAdvice">
<aop:pointcut id="afterPointcut" expression="execution(public void com..aop.*.*(..))"/>
<aop:after method="afterMethodCall" pointcut-ref="afterPointcut"/>
</aop:aspect>
</aop:config>
<>aop:after, <>aop:before 동시에 사용 가능
<aop:aspect ref="beforeAdvice">
<aop:pointcut id="beforePointcut"
expression="execution(public void com..aop.*.*(..))" />
<aop:before method="beforeMethodCall"
pointcut-ref="beforePointcut" />
</aop:aspect>
<aop:aspect ref="afterAdvice">
<aop:pointcut id="afterPointcut"
expression="execution(public void com..aop.*.*(..))" />
<aop:after method="afterMethodCall"
pointcut-ref="afterPointcut" />
</aop:aspect>
<>aop:around - Target 메소드 실행 전,후 적용
내가 Advice를 적용할 위치(메소드)를 기준으로 before과 after가 실행된다.
method가 리턴값이 있을 때는 그 값을 받아놔야만, after한테 값을 넘겨줄 수 있다. (result = return값 받는 변수)
(before + after 합친게 MyAround라고 생각하면 됨)
MyAroundAdvice.java
@Component
public class MyAroundAdvice {
public Object aroundMethodCall(
ProceedingJoinPoint joinPoint) {
Object result = null;
// result = return값을 받는 변수
try {
System.out.println("메소드 실행 전(round)");
result = joinPoint.proceed();
// 메소드를 실행 시키는 것 => 반환값이 있다면 반환값 받아놓고
System.out.println("메소드 실행후(round)");
// 그 받은 리턴값을 원하는 곳으로 되돌려줌
} catch (Throwable e) {
// exception 가지고는 AOP에 대한건 예외처리가 안됨
// Throwable 이용
}
return result;
}
}
app-context.xml
<aop:config>
<aop:aspect ref="aroundAdvice">
<aop:pointcut id="aroundPointcut" expression="execution(* com..aop.*.*(..))"/>
<aop:around method="aroundMethodCall" pointcut-ref="aroundPointcut"/>
</aop:aspect>
</aop:config>
Annotation을 적용한 AOP 예제
1. app-context.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<description>Example configuration to get you started.</description>
<context:component-scan base-package="com.exe.aop" />
<aop:aspectj-autoproxy/> <!-- AOP를 annotation으로 사용하겠다 -->
</beans>
<>aop:after-returning - 메소드 정상 실행 후
MyAfterReturningAdvice.java
package com.exe.aop;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAfterReturningAdvice {
@AfterReturning("execution(* com..aop.*.*(..))")
public void afterReturningMethodCall() {
System.out.println("메소드 실행 완료 (return) ");
//리턴값이 돌려졌따는건 메소드가 에러없이 잘 실행됐다는 말
//그걸 체크하라
}
}
@Aspect는 <aop:aspect ref="afterReturningAdvice"> 와 같은말
@AfterReturning("execution(* com..aop.*.*(..))") 는 아래와 같은말
<aop:pointcut id="afterThrowingPointcut" expression="execution(* com..aop.*.*(..))"/>
<aop:after-throwing method="afterThrowingMethodCall" pointcut-ref="afterThrowingPointcut"/>
<>aop:after-throwing - 메소드 실행 에러가 났을 때 적용 (예외 처리 작동)
MyAfterThrowingAdvice.java
package com.exe.aop;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAfterThrowingAdvice {
@AfterThrowing("execution(* com..aop.*.*(..))")
public void afterThrowingMethodCall() {
System.out.println("메소드 실행 에러가 났을 때만 뜨는 메세지");
}
}
TargetA.java - TargetA 객체에 일부로 에러내보았다.
package com.exe.aop;
import org.springframework.stereotype.Component;
@Component("targetA")// targetA란 이름으로 객체생성
public class TargetA {
public void doSomething1() {
System.out.println("TargetA.doSomething1");
}
public void doSomething2() {
System.out.printlns("TargetA.doSomething2");
} // 일부로 lns라고 적어서 에러를 냄
public void doAnother1() {
System.out.println("TargetA.doAnother1");
}
public void doAnother2() {
System.out.println("TargetA.doAnother2");
}
}
-> TargetA.doSomething2만 실행 안됨
'Spring 3.0 - 4.3' 카테고리의 다른 글
MyBatis를 이용한 게시판 만들기 (0) | 2019.11.19 |
---|---|
Spring DAO 를 이용한 게시판 만들기 (0) | 2019.11.18 |
Spring Web MVC를 이용하여 웹 서버 띄우기 (0) | 2019.11.14 |
Spring 3.0 - Annotation을 이용한 의존성 주입 (0) | 2019.11.13 |
Spring 3.0 - DI(Dependency Injection) 의 이해 (0) | 2019.11.13 |