day63 - Spring Framework(스프링, AOP)
[AOP]
- Aspect Oriented Programming. 관점 지향 프로그래밍으로 어플리케이션에서 전반적으로 사용되는 공통 기능들을 공통 관심 사항으로 구분한다.
- 중복 코드를 제거하고 그로 인한 간경성과 생산성을 얻을 수 있다.
- 재사용성과 유지보수성 또한 증가한다.
- Advice
언제 공통 관심 기능을 핵심 로직에 적용할 것인 지를 정의한다.
- Jointpoint
Advice 가 적용 가능한 지점을 의미한다. 메소드 호출, 필드값 변경 등이 이에 해당한다.
- Pointcut
Joinpoint의 부분 집합으로써 실제로 Advice가 적용 되는 Jointpoint를 말한다. 정규 표현식이나 Aspectj의 문법을 사용하여 Pointcout을 정의할 수 있다.
- Aspect
- 여러 객체에 공통으로 적용되는 공통 관심 사항을 Aspect라고 한다.
[Advice의 종류]
- Before Advice
대상 객체의 메서드 호출 전에 공통 기능을 실행한다.
- After Returning Advice
대상 객체의 메서드가 예외 없이 실행한 이후에 공통 기능을 실행한다.
- After Throwing Advice
대상 객체의 메서드 실행 도중 예외가 발생시에 공통 기능을 실행한다.
- After Advice
대상 객체의 메서드 실행 도중 예외가 발생 했는지 여부와 상관없이 메서드 실행 후 공통 기능을 실행한다.
(try catch finally 에서 finally 블록과 비슷한 역할이다.)
- Around Advice
대상 객체의 메서드 실행 전, 후 또는 예외 발생 시점에 공통 기능을 실행 시에 사용한다. 범용으로 사용 가능하다.
[Main2.java]
package ch03_AOPXmlAnno;
import org.springframework.context. ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import di06.Article;
import di06.ArticleNotFoundException;
import di06.ReadArticleService;
public class Main2 {
public static void main(String[] args) {
String[] config = {"ch03_AOPXmlAnno/di.xml", "ch03_AOPXmlAnno/aop2.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
ReadArticleService service = ctx.getBean("readArticleService", ReadArticleService.class);
try {
Article a1 = service.getArticleAndReadCnt(1); //A
Article a2 = service.getArticleAndReadCnt(1); //B
System.out.println("[main] a1 == a2 : " + (a1==a2));
service.getArticleAndReadCnt(0); //C
} catch (ArticleNotFoundException e) {
System.out.println("[main]" + e.getMessage());
}
}
}
[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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="LoggingAdvice" class="di06.LoggingAdvice" />
<bean id="cacheAdvice" class="di06.ArticleCacheAdvice"/>
<aop:config>
<aop:aspect id="LoggingAspect" ref="LoggingAdvice">
<aop:pointcut id="publicMethod"
expression="execution (public * di06.*Service.*(..))" />
<aop:before method="before"
pointcut="execution (public * di06.*Service.*(..))" />
<aop:after-returning method="afterReturning"
pointcut-ref="publicMethod" returning="ret" />
<aop:after-throwing method="afterThrowing"
throwing="ex" pointcut-ref="publicMethod" />
<aop:after method="afterFinally"
pointcut-ref="publicMethod" />
</aop:aspect>
<aop:aspect id="cacheAspect" ref="cacheAdvice">
<aop:around method="cache" pointcut="execution(public * *..ReadArticleServiceImpl.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
[LoggingAdvice.java]
package di06;
public class LoggingAdvice {
public void before() {
System.out.println("[LA]메서드 실행 전(before) 전처리 수행함.");
}
public void afterReturning(Object ret) {
System.out.println("[LA]메서드 정상 처리(afterReturning) 후 수행함 리턴값: " + ret);
}
public void afterThrowing(Throwable ex) {
System.out.println("[LA]메서드 예외 발생 후(afterThrowing) 수행함 예외:" +ex.getMessage());
}
public void afterFinally() {
System.out.println("[LA]메서드 실행 후(afterFinally) 후처리 수행함");
}
}