Advice 동작시점
동작시점 | 설명 |
Before | 메소드 실행 전에 동작 |
After | 메소드 실행 후에 동작 |
After-returning | 메소드가 정상적으로 실행된 후에 동작 |
After-throwing | 예외가 발생한 후에 동작 |
Around | 메소드 호출 이전, 이후, 예외발생 등 모든 시점에서 동작 |
예제 실습
[interface] Person.java
package com.java.aop03;
public interface Person {
public void work();
}
Student.java
package com.java.aop03;
public class Student implements Person {
@Override
public void work() {
System.out.println("학생은 공부를 합니다.");
}
}
Teacher.java
package com.java.aop03;
public class Teacher implements Person { //핵심클래스
@Override
public void work() { //핵심 함수
System.out.println("선생님은 강의를 합니다.");
}
}
PAspect.java
package com.java.aop03;
import org.aspectj.lang.JoinPoint;
public class PAspect { // 공통클래스(aspect)
public void open(JoinPoint joinPoint) { //공통함수(advice), 핵심코드(JoinPoint)
System.out.println("수업시작 -> 강의장에 들어온다.");
}
public void close(JoinPoint joinPoint) {
System.out.println("수업끝 -> 강의장을 나간다.");
}
}
appCTX.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-3.1.xsd">
<!-- 핵심클래스 -->
<bean id="teacher" class="com.java.aop03.Teacher"/>
<bean id="student" class="com.java.aop03.Student"/>
<!-- 공통클래스 -->
<bean id="pAspect" class="com.java.aop03.PAspect"/>
<!-- AOP -->
<aop:config>
<aop:aspect id="aspect" ref="pAspect">
<aop:pointcut expression="within(com.java.aop03.*)" id="pMethod"/>
<aop:before method="open" pointcut-ref="pMethod"/>
<aop:after method="close" pointcut-ref="pMethod"/>
</aop:aspect>
</aop:config>
</beans>
MainClass.java
package com.java.aop03;
import org.springframework.context.support.GenericXmlApplicationContext;
public class MainClass {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:com/java/aop03/appCTX.xml");
Person student = (Person) ctx.getBean("student");
student.work();
System.out.println();
Person teacher = (Person) ctx.getBean("teacher");
teacher.work();
System.out.println();
}
}
실행결과
에러 발생 시키기
PAspect.java
package com.java.aop03;
import org.aspectj.lang.JoinPoint;
public class PAspect { // 공통클래스(aspect)
//핵심전
public void open(JoinPoint joinPoint) { //공통함수(advice), 핵심코드(JoinPoint)
System.out.println("수업시작 -> 강의장에 들어온다.");
}
//핵심후
public void close(JoinPoint joinPoint) {
System.out.println("수업끝 -> 강의장을 나간다.");
}
//에러
public void error(JoinPoint joinPoint) {
System.out.println("떠들어 강의에서 쫓겨남..흡 식권도없음!");
}
//정상
public void eat(JoinPoint joinPoint) {
System.out.println("점심식사를 맛나게 함!!");
}
}
appCTX.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-3.1.xsd">
<!-- 핵심클래스 -->
<bean id="teacher" class="com.java.aop03.Teacher"/>
<bean id="student" class="com.java.aop03.Student"/>
<!-- 공통클래스 -->
<bean id="pAspect" class="com.java.aop03.PAspect"/>
<!-- AOP -->
<aop:config>
<aop:aspect id="aspect" ref="pAspect">
<aop:pointcut expression="within(com.java.aop03.*)" id="pMethod"/>
<aop:before method="open" pointcut-ref="pMethod"/>
<aop:after method="close" pointcut-ref="pMethod"/>
<aop:after-returning method="eat" pointcut-ref="pMethod"/>
<aop:after-throwing method="error" pointcut-ref="pMethod"/>
</aop:aspect>
</aop:config>
</beans>
Student.java
package com.java.aop03;
import java.util.Scanner;
public class Student implements Person {
@Override
public void work() {
System.out.println("학생은 공부를 합니다.");
Scanner sc = new Scanner(System.in);
System.out.println("수입력: ");
int su = sc.nextInt();
if(su==5) System.out.println(su/0);
sc.close();
}
}
+ 다른 방법
PAspect.java
package com.java.aop04;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class PAspect { // 공통클래스(aspect)
public void sub(ProceedingJoinPoint joinPoint) {
try {
//핵심함수전
System.out.println("수업시작 -> 강의장에 들어온다.");
//핵심코드
joinPoint.proceed();
//정상
System.out.println("점심식사를 맛나게 함!!");
} catch (Throwable e) {
//에러
System.out.println("떠들어 강의에서 쫓겨남..흡 식권도없음!");
} finally {
//핵심함수 후
System.out.println("수업끝 -> 강의장을 나간다.");
}
}
}
appCTX.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-3.1.xsd">
<!-- 핵심클래스 -->
<bean id="teacher" class="com.java.aop04.Teacher"/>
<bean id="student" class="com.java.aop04.Student"/>
<!-- 공통클래스 -->
<bean id="pAspect" class="com.java.aop04.PAspect"/>
<!-- AOP -->
<aop:config>
<aop:aspect id="aspect" ref="pAspect">
<aop:pointcut expression="within(com.java.aop04.*)" id="pMethod"/>
<aop:around method="sub" pointcut-ref="pMethod"/>
</aop:aspect>
</aop:config>
</beans>
MainClass.java
package com.java.aop04;
import org.springframework.context.support.GenericXmlApplicationContext;
public class MainClass {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:com/java/aop04/appCTX.xml");
Person student = (Person) ctx.getBean("student");
student.work();
System.out.println();
Person teacher = (Person) ctx.getBean("teacher");
teacher.work();
System.out.println();
}
}
위의 방식과 동일한 결과창
스프링 @AOP 실습
스프링 AOP를 사용하여 성능 측정해보기
Annotation을 활용하여 성능 측정을 해보자. 성능을 측정하고 싶은 메소드에 annotation을 붙여서 콘솔에 성능이 출력되도록 할 것이다.
LogExecutionTime.java
package org.springframework.samples.petclinic.owner;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
메소드에 LogExecutionTime이라는 annotation을 추가하자. @Target은 어디에 쓸 수있는지 메소드에게 알려주는 annotation이고, @Retention은 annotation의 정보를 언제까지 유지할 것인지를 알려주는 annotation이다.
이렇게 만들어 놓고 추가한다고 실행하면 동작하느냐? 아니다. 그냥 만들기만 하면 주석과 다름없다. 이러한 annotation을 읽어서 처리하는 Aspect를 만들도록 하자.
LogAspect.java
package org.springframework.samples.petclinic.owner;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
@Component
@Aspect
public class LogAspect {
Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint JoinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object proceed = joinPoint.proceed();
stopWatch.stop();
logger.info(stopWatch.prettyPrint());
return proceed;
}
}
빈으로 등록하기 위해서 @Component라는 annotation을 붙여주고, @Aspect임을 알려준다. slf4j로 Logger를 만들고, @Around 이하의 코드는 어드바이스라고 하는데, @Around라는 annotation으로 joinPoint라는 파라미터를 받을 수 있다. 이 파라미터는 타겟, 여기서는 @LogExecutionTime이 붙어있는 메소드를 말한다.
이 Aspect는 프록시 패턴 기반으로 동작하는 AOP이다.
'Coding > SPRING' 카테고리의 다른 글
[Spring] AOP(Aspect Oriented Programming)=Part.1 (0) | 2022.04.07 |
---|---|
[Spring] 다운로드 (0) | 2022.04.07 |
[Spring] DI(Depedency Injection)의존성 주입&IoC(Inversion of Control)제어의 역전 (0) | 2022.04.06 |