4. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
Pointcut은 모든 Join Point중 Advice가 Weaving 되어야 할 Join Point의 집합을 정의한 것이다.
교차점(PointCut)은 특정한 클래스의 특정한 메소드가 특정한 기준과 일치하는지를 판단한다. 만약 그
메소드가 실제로 일치한다면 충고가 적용된다.
스프링은 충고를 받으려고 하는 클래스와 메소드의 관점에서 교차점을 정의하며 충고는 클래스의 이름
과 메소드 시그네처(Method Signature)와 같은 특징에 기초하여 대상 클래스와 메소드에 엮인다.
스프링의 교차점 프레임워크를 위한 핵심 인터페이스는 PointCut, PointCut은 메소드와 클래스에 기초
하여 충고를 어디에 엮을지 결정한다.
Pointcut 구현체를 사용하려면 먼저 Advisor 인터페이스의 인스턴스를 생성하거나 좀 더 구체적으로
PointcutAdvisor 인터페이스의 인스턴스를 생성해야 한다.
6. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
PointCut Interface
public interface PointCut {
ClassFilter getClassFilter(); //클래스의 특정메소드에 pointcut적용여부판단
MethodMatcher getMethodMatcher();
}
ClassFilter Interface : 인자로 넘어온 Class가 충고를 받아야 하는지를 판단해야 한다.
public interface PointCut {
ClassFilter getClassFilter(); //클래스의 특정메소드에 pointcut적용여부판단
MethodMatcher getMethodMatcher();
}
7. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
: matches(Method ,Class) 메소드는 대상 Class와 Method를 기초로 메소드가 충고를 받을 수 있는지의
여부를 판단한다. true가 리턴되면 어떤 유형의 MethodMatcher인지 판단하기 위해 isRuntime()이 호출
된다. Static 교차점(pointcut)은 항상 실행되는 교차점을 정의하며 이 경우 isRuntime()은 false를 return
하며 동적 교차점(Dynamic Pointcut)은 런타임시의 메소드 인자를 확인하여 충고가 실행되어야 하는지를
결정한다. matches 메소드와 마찬가지로 isRuntime()은 프록시 객체가 생성될 때 오직 한번만 호출된다.
MethodMatcher
public interface MethodMatcher {
boolean matches(Method m, Class targetClass);
public boolean isRuntime();
public boolean matches(Method m, Class target, Object[] args);
}
8. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
: Aspect는 행동을 정의한 충고와 실행돼야 할 위치를 정의한 교차점(Pointcut)의 조합으로 이루어 진다.
스프링에서는 이를 위해 충고자라는 것을 제공한다. 충고자는 충고(Advice)와 교차점(Pointcut)을 하나의
객체로 합친 것 이다.
충고자(Advisor)
public interface PointcutAdvisor {
Pointcut getPointcut();
Advice getAdvice();
}
9. 3. Spring AOP((Spring Aspect Oriented Programming)
: StaticMethodMatcherPointcut을 상속할 때는 matches 메소드만 구현하면 되지만 올바른
타입의 메소드만 어드바이스가 적용되도록 할려면 getClassFilter() 메소드를 오버라이드
하는 것이 좋다.
File -> New -> Spring Legacy Project
Project name : springonj
Simple Spring Maven 선택
[pom.xml에 아래 의존성 추가]
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
3-5. 포인트컷(Pointcut)
3-5-1. 포인트컷(Pointcut) - StaticMethodMatcherPointCut
10. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-1. 포인트컷(Pointcut) - StaticMethodMatcherPointCut
[First.java]
package onj.edu.aop1;
public class First {
public void one() {
System.out.println("First One...");
}
public void two() {
System.out.println("First Two...");
}
}
[Second.java]
package onj.edu.aop1;
public class Second {
public void one() {
System.out.println("Second
One...");
}
public void two() {
System.out.println("Second
Two...");
}
}
11. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-1. 포인트컷(Pointcut) - StaticMethodMatcherPointCut
[SimpleAdvice.java]
package onj.edu.aop1;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class SimpleAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation)
throws Throwable {
System.out.println(invocation.getMethod().get
Name());
Object o = invocation.proceed();
System.out.println("... SimpleAdvice의 충고가
적용됨 ...");
return o;
}
}
[SimpleStaticPointcut.java]
package onj.edu.aop1;
import java.lang.reflect.Method;
import
org.springframework.aop.support.StaticMethodMatcherPoint
cut;
public class SimpleStaticPointcut extends
StaticMethodMatcherPointcut {
// 아래는First.class의 one()의 실행 전/후 충고가 적용된다.
public boolean matches(Method method,
Class<?> cls) {
return
("one".equals(method.getName()) && cls == First.class);
}
}
12. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-1. 포인트컷(Pointcut) - StaticMethodMatcherPointCut
[StaticPointcutExam.java]
public class StaticPointcutExam {
public static void main(String[] args) {
First f = new First();
Second s = new Second();
First proxyFirst;
Second proxySecond;
//pointcut, advice, advisor 생성
Pointcut pc = new SimpleStaticPointcut();
Advice advice = new SimpleAdvice();
Advisor advisor = new DefaultPointcutAdvisor(pc, advice);
//First 프록시 생성
ProxyFactory pf = new ProxyFactory();
pf.addAdvisor(advisor);
pf.setTarget(f); //First.class를 타겟으로
proxyFirst = (First)pf.getProxy();
proxyFirst.one();
proxyFirst.two();
//Second 프록시 생성
pf = new ProxyFactory();
pf.addAdvisor(advisor);
pf.setTarget(s); //Second.class를 타겟으로
proxySecond = (Second)pf.getProxy();
proxySecond.one();
proxySecond.two();
}
}
[결과]
one
First One...
... SimpleAdvice의 충고가 적용됨 ...
First Two...
Second One...
Second Two...
14. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-2. 포인트컷(Pointcut) - DynamicMethodMatcherPointCut
: DynamicMethodMatcherPointcut에서 충고가 적용되는 메소드는 모든 메소드를 검사하는 초
기화 단계, 메소드가 처음 호출되는 시점에 걸쳐 두 번의 정적 검사를 받게 된다. 이 처럼 동적
포인트 컷은 정적 포인트 컷 보다 유연하게 적용될 수 있지만 성능 부담을 고려해 필요한 경우만
사용해야 한다.
[First.java]
package onj.edu.aop2;
public class First {
public void one(int i) {
System.out.println("First One... i = " + i);
}
public void two() {
System.out.println("First Two...");
}
}
15. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-2. 포인트컷(Pointcut) - DynamicMethodMatcherPointCut
[SimpleAdvice.java]
package onj.edu.aop2;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//주변충고
public class SimpleAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getMethod().getName());
Object o = invocation.proceed();
System.out.println("... SimpleAdvice의 충고가 적용됨 ...");
return o;
}
}
16. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-2. 포인트컷(Pointcut) - DynamicMethodMatcherPointCut
[SimpleDynamicPointcut.java]
package onj.edu.aop2;
import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import
org.springframework.aop.support.DynamicMethodMatcherPointcut;
/* DynamicMethodMatcherPointcut은
* matches(Method method, Class<?> cls, Object[] args) 반드시 구
현해야함
* 정적체크를 위해서는 matches(Method method, Class<?> cls)도
같이 구현해야 한다.
*/
public class SimpleDynamicPointcut extends
DynamicMethodMatcherPointcut {
//메소드 이름이 one 인 경우 true 즉 충고가 주입된다.아래는 정적체크
//스프링은 two 메소드에 대해서는 동적 검사를 진행 안함
public boolean matches(Method method, Class<?> cls) {
System.out.println("static check :: method.getName() :: " + method.getName());
return "one".equals(method.getName());
}
//동적 검사
public boolean matches(Method method, Class<?> cls, Object[] args) {
System.out.println("Dynamic Check : " + ((Integer)args[0]).intValue());
int i = ((Integer)args[0]).intValue();
return i > 100;
}
//First.class만 충고가 주입된다.
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class <?> cls) {
return (cls == First.class);
}
};
}
}
17. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-2. 포인트컷(Pointcut) - DynamicMethodMatcherPointCut
[DynamicPointcutExam.java]
package onj.edu.aop2;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class DynamicPointcutExam {
public static void main(String[] args) {
First target = new First();
//어드바이저 생성
Advisor advisor = new DefaultPointcutAdvisor(new
SimpleDynamicPointcut(), new SimpleAdvice());
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
First proxy = (First)pf.getProxy();
proxy.one(99);
proxy.one(101);
proxy.two();
}
}
[결과]
18. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-3. 포인트컷(Pointcut) - DynamicMethodMatcherPointCut
: 가끔은 메소드 시그네처, 리턴형은 무시하고 메소드 이름으로 적용여부를 판단하는 포인트 컷이 필요하다.
이때 사용되는 포인트 컷이 NameMatchMethodPointcut 이다. 이번에는 포인트 컷으로 사용할 클래스를 만
들지 않아도 되며 직접 NameMatchMethodPointcut을 new 하면 된다.
[First.java]
package onj.edu.aop3;
public class First {
public void one() {
System.out.println("First One...");
}
public void two() {
System.out.println("First Two...");
}
public void three() {
System.out.println("First Three...");
}
}
19. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-3. 포인트컷(Pointcut) - DynamicMethodMatcherPointCut
[SimpleAdvice.java]
package onj.edu.aop3;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class SimpleAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getMethod().getName());
Object o = invocation.proceed();
System.out.println("... SimpleAdvice의 충고가 적용됨 ...");
return o;
}
}
20. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-3. 포인트컷(Pointcut) - DynamicMethodMatcherPointCut
[NameMatchMethodPointcutExam.java]
package onj.edu.aop3;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
public class NameMatchMethodPointcutExam {
public static void main(String[] args) {
First target = new First();
//Advisor
NameMatchMethodPointcut pc = new
NameMatchMethodPointcut();
pc.addMethodName("one");
pc.addMethodName("two");
Advisor advisor = new DefaultPointcutAdvisor(pc, new
SimpleAdvice());
//Proxy
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
First f = (First)pf.getProxy();
f.one();
f.two();
f.three();
}
}
[결과]
21. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-4. 포인트컷(Pointcut) - JdkRegexpMethodPointcut
[First.java]
package onj.edu.aop4;
public class First {
public void hello1() {
System.out.println("hello1 ... ");
}
public void hello2() {
System.out.println("hello2 ... ");
}
public void sayHello() {
System.out.println("sayHello ... ");
}
}
: 앞 예제 처럼 메소드 이름을 정확히 알지 못하는 경우, 이름대신 패턴을 사용하여 포인트 컷을 생성할 수 있
는데 이때 사용되는 포인트 컷이 JdkRegexpMethodPointcut 이다.
22. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-4. 포인트컷(Pointcut) - JdkRegexpMethodPointcut
[RegExpExam.java]
public class RegExpExam {
public static void main(String[] args) {
First target = new First();
//Advisor
JdkRegexpMethodPointcut pc = new JdkRegexpMethodPointcut();
//스프링은 비교할 때 onj.edu.aop4.RegExam.hello1을 사용한다.
//.* 어떤패키지에있던지... hello를 담고 있으면 OK
pc.setPattern(".*hello.*");
Advisor advisor = new DefaultPointcutAdvisor(pc, new
SimpleAdvice());
//Proxy
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
First f = (First)pf.getProxy();
f.hello1();
f.hello2();
f.sayHello();
}
}
[결과]
: Pointcut은 Advice가 적용될 메소드를
골라야 하는데 Method Signature에 일
치하는 패턴을 지정하는 방법을 주로 사
용하는 포인트 컷이다.
org.springframework.aop.support.Jdkre
gexpMethodPointcut JDK1.4이상 사용
23. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-4. 포인트컷(Pointcut) - JdkRegexpMethodPointcut
<bean id=“smallMartPointcut”
class=“org.springframework.aop.support.JdkregexpMethodPointcut”>
<!-- 어떤클래스든 관계없고 get으로 시작하는 메소드
<property name=“pattern” value=“*.get*”/>
</bean>
<bean id=“smallMartAdvisor”
class=“org.springframework.aop.support.DefaultPointcutAdvisor”>
<property name=“advice” ref=“beforeLogging”/>
<property name=“pointcut” ref= “smallMartPointcut”/>
</bean>
Pointcut을 정의했으면 이를 Advice에 결합시킬 수 있다.
앞에서 pointcut을 만들고 advice와 결합을 시켰는데 하나의 빈에 pointcut과 advice를 동시에 정의할 수 있는 특별한 Advisor가 있다.
(org.springframework.aop.support.RegexpMethodPointcutAdvisor)
<bean id=“smallMartAdvisor” class=“org.springframework.aop.support.
RegexpMethodPointcutAdvisor”>
<property name=“advice” ref=“beforeLogging”/>
<property name=“pattern” value=“*.get*”/>
</bean>
24. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-5. 포인트컷(Pointcut) - AspectJExpressionPointcut
: Jdk 정규 표현식외 AspectJ 포인트컷 표현식 언어를 통해 포인트 컷을 선언할 수도 있다. JDK 정규식 보다
많이 사용되며 스프링은 AspectJExpressionPointcut 클래스를 제공하며 aspectjrt.jar, aspectjweaver.jar 두
라이브러리 파일이 필요하다.
[AspectJPointcutExam.java]
public static void main(String[] args) {
First target = new First();
//Advisor
AspectJExpressionPointcut pc = new AspectJExpressionPointcut();
//인자, 반환 관계없이 hello로 시작하는...
pc.setExpression("execution(* hello*(..))");
Advisor advisor = new DefaultPointcutAdvisor(pc, new
SimpleAdvice());
//Proxy
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
First f = (First)pf.getProxy();
f.hello1();
f.hello2();
f.sayHello();
}
25. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-5. 포인트컷(Pointcut) - AspectJExpressionPointcut
XML 기반 사용 예
<bean id=“smallMartPointcut” class=“org.springframework.aop.aspectj.
AspectJExpressionPointcut”>
<!–모든 리턴형에 대해, 모든 클래스의 getProduct 메소드
<property name=“expression” value=“execution(* *.getProducts(..)”/>
</bean>
아래처럼 한번에도 가능하다.
<bean id=“smallMartAdvisor” class=“org.springframework.aop.aspectj.
AspectJExpressionPointcutAdvisor”>
<property name=“advice” ref=“beforeLogging”/>
<property name=“expression” value=“execution(* *.getProducts(..)”/>
</bean>
26. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-6. 포인트컷(Pointcut) - AnnotationMatchingPointcut
[AdviceRequired.java]
package onj.edu.aop6;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
//이 어노테이션을 타입레벨과 메소드레벨에서 적용할수있도록
@Target({ElementType.TYPE, ElementType.METHOD}) public @interface
AdviceRequired { //interface를 어노테이션으로 선언
}
: Application이 어노테이션 기반이라면 커스텀 어노테이션을 사용해서 포인트컷을 지정하고 어드바이스를
특정 어노테이션이 적용된 모든 메소드 또는 타입에 적용하고 싶을 때가 있다. 스프링은 어노테이션을 사용
해서 포인트컷을 정의할 수 있도록 해주는 AnnotationMatchingPointcut 클래스를 제공한다.
[First.java]
package onj.edu.aop6;
public class First {
@AdviceRequired //어드바이스가 적용될 것
public void hello() {
System.out.println("hello1 ... ");
}
public void sayHello() {
System.out.println("sayHello ... ");
}
}
27. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-6. 포인트컷(Pointcut) - AnnotationMatchingPointcut
[SimpleAdvice.java]
package onj.edu.aop6;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class SimpleAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(invocation.getMethod().getName());
Object o = invocation.proceed();
System.out.println("... SimpleAdvice의 충고가 적용됨 ...");
return o;
}
}
28. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-6. 포인트컷(Pointcut) - AnnotationMatchingPointcut
[AnnotationPointcutExam.java]
public class AnnotationPointcutExam {
public static void main(String[] args) {
First target = new First();
//Advisor, 메소드를 호출하면서 지정한 어노테이션이 적용된 모든 메소드에 어드바이스를 적용
AnnotationMatchingPointcut pc =
AnnotationMatchingPointcut.forMethodAnnotation(AdviceRequired.class);
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleAdvice());
//Proxy
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
First f = (First)pf.getProxy();
f.hello();
f.sayHello();
}
}
[결과]
29. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-7. 포인트컷(Pointcut) - ControllFlowPointcut
[First.java]
package onj.edu.aop7;
public class First {
public void hello() {
// 특정 메소드인 myAdvice()에서 Call할 때 충고 적용함
System.out.println("hello ... ");
}
}
: 특정 메소드 하위의 모든 메소드 호출 또는 특정 클래스 하위의 모든 메소드 호출에 사용한다
[SimpleBeforeAdvice.java]
package onj.edu.aop7;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class SimpleBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object args[], Object target) throws Throwable {
System.out.println("Before Method ::" + method);
}
}
30. 3. Spring AOP((Spring Aspect Oriented Programming)
3-5. 포인트컷(Pointcut)
3-5-7. 포인트컷(Pointcut) - ControllFlowPointcut
[ControlFlowExam.java]
public class CaontrolFlowExam {
public static void main(String[] args) {
ControlFlowExam c = new ControlFlowExam();
c.go();
}
void go() {
First target = new First();
//ControlFlowExam.class의 myAdvice() 가 호출하는 모든 메소드에 충고적용
Pointcut pc = new ControlFlowPointcut(ControlFlowExam.class, "myAdvice");
Advisor advisor = new DefaultPointcutAdvisor(pc, new SimpleBeforeAdvice());
//Proxy
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisors(advisor);
First f = (First)pf.getProxy();
//Normal Invoke
f.hello();
//ControlFlowExam.myAdvice()
myAdvice(f);
}
void myAdvice(First f) {
f.hello();
}
}
[결과]
31. Any Questions ?
THANK YOU
FOR YOUR ATTENTION
무료국비지원교육 / 구로자바학원 _ 탑크리에듀 교육센터
http://www.topcredu.co.kr