(스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크...

18
스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis) 3-5. 포인트컷(Pointcut) Pointcut은 모든 Join Point중 Advice가 Weaving 되어야 할 Join Point의 집합을 정의한 것이 다. 교차점(PointCut)은 특정한 클래스의 특정한 메소드가 특정한 기준과 일치하는지를 판단한다. 만약 그 메소드가 실제로 일치한다면 충고가 적용된다. 스프링은 충고를 받으려고 하는 클래스와 메소드의 관점에서 교차점을 정의하며 충고는 클래 스의 이름과 메소드 시그네처(Method Signature)와 같은 특징에 기초하여 대상 클래스와 메 소드에 엮인다. 스프링의 교차점 프레임워크를 위한 핵심 인터페이스는 PointCut, PointCut은 메소드와 클래 스에 기초하여 충고를 어디에 엮을지 결정한다. Pointcut 구현체를 사용하려면 먼저 Advisor 인터페이스의 인스턴스를 생성하거나 좀 더 구체 적으로 PointcutAdvisor 인터페이스의 인스턴스를 생성해야 한다.

Upload: 3-2

Post on 12-Apr-2017

220 views

Category:

Education


2 download

TRANSCRIPT

Page 1: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

스프링프레임워크 & 마이바티스

(Spring Framework, MyBatis)

3-5. 포인트컷(Pointcut)

Pointcut은 모든 Join Point중 Advice가 Weaving 되어야 할 Join Point의 집합을 정의한 것이

다.

교차점(PointCut)은 특정한 클래스의 특정한 메소드가 특정한 기준과 일치하는지를 판단한다.

만약 그 메소드가 실제로 일치한다면 충고가 적용된다.

스프링은 충고를 받으려고 하는 클래스와 메소드의 관점에서 교차점을 정의하며 충고는 클래

스의 이름과 메소드 시그네처(Method Signature)와 같은 특징에 기초하여 대상 클래스와 메

소드에 엮인다.

스프링의 교차점 프레임워크를 위한 핵심 인터페이스는 PointCut, PointCut은 메소드와 클래

스에 기초하여 충고를 어디에 엮을지 결정한다.

Pointcut 구현체를 사용하려면 먼저 Advisor 인터페이스의 인스턴스를 생성하거나 좀 더 구체

적으로 PointcutAdvisor 인터페이스의 인스턴스를 생성해야 한다.

Page 2: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

PointCut Interface

public interface PointCut {

ClassFilter getClassFilter(); //클래스의 특정메소드에 pointcut적용여부판단

MethodMatcher getMethodMatcher();

}

ClassFilter Interface : 인자로 넘어온 Class가 충고를 받아야 하는지를 판단해야 한다.

public interface ClassFilter {

boolean matches(Class class);

}

MethodMatcher

public interface MethodMatcher {

boolean matches(Method m, Class targetClass);

public boolean isRuntime();

public boolean matches(Method m, Class target, Object[] args);

}

matches(Method ,Class) 메소드는 대상 Class와 Method를 기초로 메소드가 충고를 받을 수 있는

Page 3: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

지의 여부를 판단한다. true가 리턴되면 어떤 유형의 MethodMatcher인지 판단하기 위해

isRuntime()이 호출된다. Static 교차점(pointcut)은 항상 실행되는 교차점을 정의하며 이 경우

isRuntime()은 false를 return하며 동적 교차점(Dynamic Pointcut)은 런타임시의 메소드 인자를 확

인하여 충고가 실행되어야 하는지를 결정한다. matches 메소드와 마찬가지로 isRuntime()은 프록

시 객체가 생성될 때 오직 한번만 호출된다.

충고자(Advisor)

Aspect는 행동을 정의한 충고와 실행돼야 할 위치를 정의한 교차점(Pointcut)의 조합으로 이루어

짂다. 스프링에서는 이를 위해 충고자라는 것을 제공한다. 충고자는 충고(Advice)와 교차점

(Pointcut)을 하나의 객체로 합친것 이다.

public interface PointcutAdvisor {

Pointcut getPointcut();

Advice getAdvice();

}

3-5-1. 포인트컷(Pointcut) - StaticMethodMatcherPointCut

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>

[First.java]

package onj.edu.aop1;

Page 4: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

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...");

}

}

[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().getName());

Object o = invocation.proceed();

System.out.println("... SimpleAdvice의 충고가 적용됨 ...");

return o;

}

}

[SimpleStaticPointcut.java]

Page 5: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

package onj.edu.aop1;

import java.lang.reflect.Method;

import org.springframework.aop.support.StaticMethodMatcherPointcut;

public class SimpleStaticPointcut extends StaticMethodMatcherPointcut {

// 아래는First.class의 one()의 실행 전/후 충고가 적용된다.

public boolean matches(Method method, Class<?> cls) {

return ("one".equals(method.getName()) && cls == First.class);

}

}

[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();

Page 6: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

proxySecond.one();

proxySecond.two();

}

}

[결과]

one

First One...

... SimpleAdvice의 충고가 적용됨 ...

First Two...

Second One...

Second Two...

3-5-2. 포인트컷(Pointcut) - DynamicMethodMatcherPointCut

DynamicMethodMatcherPointcut에서 충고가 적용되는 메소드는 모든 메소드를 검사하는 초

기화 단계, 메소드가 처음 호출되는 시점에 걸쳐 두 번의 정적 검사를 받게 된다. 이 처럼

동적 포인트 컷은 정적 포인트 컷 보다 유연하게 적용될 수 있지만 성능 부담을 고려해 필요

한 경우만 사용해야 한다.

[First.java]

package onj.edu.aop2;

public class First {

Page 7: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

public void one(int i) {

System.out.println("First One... i = " + i);

}

public void two() {

System.out.println("First Two...");

}

}

[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;

}

}

[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 즉 충고가 주입된다.아래는 정적체크

Page 8: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

//스프링은 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);

}

};

}

}

[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);

Page 9: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

First proxy = (First)pf.getProxy();

proxy.one(99);

proxy.one(101);

proxy.two();

}

}

[결과]

3-5-3. 포인트컷(Pointcut) - NameMatchMethodPointCut

가끔은 메소드 시그네처, 리턴형은 무시하고 메소드 이름으로 적용여부를 판단하는 포인트

컷이 필요하다. 이때 사용되는 포인트 컷이 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...");

}

Page 10: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

public void three() {

System.out.println("First Three...");

}

}

[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;

}

}

[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);

Page 11: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

pf.addAdvisor(advisor);

First f = (First)pf.getProxy();

f.one();

f.two();

f.three();

}

}

[결과]

3-5-4. 포인트컷(Pointcut) - JdkRegexpMethodPointcut

앞 예제 처럼 메소드 이름을 정확히 알지 못하는 경우, 이름대싞 패턴을 사용하여 포인트 컷

을 생성할 수 있는데 이때 사용되는 포인트 컷이 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 ... ");

}

}

Page 12: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

[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.JdkregexpMethodPointcut JDK1.4이상 사용

<bean id=“smallMartPointcut”

Page 13: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

class=“org.springframework.aop.support.JdkregexpMethodPointcut”>

<!-- 어떤클래스든 관계없고 get으로 시작하는 메소드

</bean>

Pointcut을 정의했으면 이를 Advice에 결합시킬 수 있다.

<bean id=“smallMartAdvisor” class=“org.springframework.aop.support.DefaultPointcutAdvisor”>

<property name=“advice” ref=“beforeLogging”/>

<property name=“pointcut” ref= “smallMartPointcut”/>

</bean>

앞에서 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>

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());

Page 14: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

//Proxy

ProxyFactory pf = new ProxyFactory();

pf.setTarget(target);

pf.addAdvisor(advisor);

First f = (First)pf.getProxy();

f.hello1();

f.hello2();

f.sayHello();

}

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>

3-5-6. 포인트컷(Pointcut) - AnnotationMatchingPointcut

Application이 어노테이션 기반이라면 커스텀 어노테이션을 사용해서 포인트컷을 지정하고 어

드바이스를 특정 어노테이션이 적용된 모든 메소드 또는 타입에 적용하고 싶을 때가 있다.

스프링은 어노테이션을 사용해서 포인트컷을 정의할 수 있도록 해주는

AnnotationMatchingPointcut 클래스를 제공한다.

[AdviceRequired.java]

package onj.edu.aop6;

Page 15: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

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를 어노테이션으로 선언

}

[First.java]

package onj.edu.aop6;

public class First {

@AdviceRequired //어드바이스가 적용될 것

public void hello() {

System.out.println("hello1 ... ");

}

public void sayHello() {

System.out.println("sayHello ... ");

}

}

[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;

Page 16: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

}

}

[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();

}

}

[결과]

3-5-7. 포인트컷(Pointcut) - ControllFlowPointcut

특정 메소드 하위의 모든 메소드 호출 또는 특정 클래스 하위의 모든 메소드 호출에 사용한

Page 17: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

[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);

}

}

[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();

Page 18: (스프링교육/마이바티스교육학원추천_탑크리에듀)#10.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)

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();

}

}

[결과]