官术网_书友最值得收藏!

Pointcut

A pointcut is an expression for the selection of joinpoints. It can be a collection of joinpoints used to define an advice that has to be executed. By defining pointcuts you can have control of the objects composing the application, at the points where the advices are applied.

As Spring defines method invocation joinpoints, all the methods that can be invoked on a class will be joinpoints.

These are some examples of pointcuts:

  • Methods starting with a certain prefix (such as, getter and setter)
  • Methods with a particular package (such as org.springaop.domain.*)
  • Methods that return a certain kind of output (such as public MyClass get*(...))
  • Any combination of the previous three examples

Pointcut and its components

A pointcut is the composition of a ClassFilter and a MethodMatcher. A ClassFilter narrows the matching of a pointcut or introduction to a given set of target classes, while a MethodMatcher checks whether the target method is eligible for advice.

public interface Pointcut {
public ClassFilter getClassFilter ();
public MethodMatcher getMethodMatcher();
}

The getClassFilter method is called first, to check if it can be applied to the class used.

The ClassFilter interface that filters the classes is composed in this way:

public interface ClassFilter {
public boolean matches(Class clazz);
public static final ClassFilter TRUE = TrueClassFilter.INSTANCE;
}

Using the constant ClassFilter TRUE, we obtain a match for all classes.

In its implementation, it will return a Boolean value according to whether or not the input parameter belongs to the wanted type.

Then, the getMethodMatcher method of the Pointcut interface is called. The MethodMatcher interface is composed in this way:

public interface MethodMatcher {
boolean matches(Method m, Class targetClass);
boolean isRuntime();
boolean matches(Method m, Class targetClass, Object[] args);
}

The first method that's called is isRuntime(). It tells Spring whether the MethodMatcher is static or dynamic:

  1. If the result is false, it's a static MethodMatcher and Spring calls the method matches(Method, Class) once for every method on the target class, caching the return value for subsequent invocations.
  2. If the result is true, it's a dynamic MethodMatcher. Spring does a static check calling matches(Method m, Class targetClass) the first time to check the applicability. If the result is true, for every invocation the matches(Method m, Class targetClass, Object[] args) is called.

In this way, the checkup is done only the first time, and the subsequent times the cached value is recovered. From this, we understand that unless we need the flexibility of having a dynamic MethodMatcher, it's better to use the static one.

Spring provides pointcuts that are ready to use, so normally, there's no need to implement your pointcut. Pointcuts that are ready to use provided by Spring are:

  1. NameMatchMethodPointcut
  2. RegexpMethodPointcut
  3. StaticMethodMatcherPointcut
  4. DynamicMethodMatcherPointcut

NameMatchMethodPointcut

Using the NameMatchMethodPointcut method, you can create a pointcut that performs simple matching against a list of method names. This class is used for the programmatic creation of proxies, and for configurations in the Spring factory with Setter Injection.

The full qualified name of the NameMAtchMethodPointcut class is:

org.springframework.aop.support.NameMatchMethodPointcut

The following methods are available:

  1. NameMatchMethodPointcut addMethodName(String methodName)
  2. void setMappedName(String methodName)
  3. void setMappedNames(String methodName)

The two setter methods are used for Setter Injection. The addMethodName method is used for the addition in a simple way of the names of the necessary methods. To allow calling addMethodName several times to add all the required method names, this is returned.

Pointcut pc = new
NameMatchMethodPointcut().addMethodName("setStartDate").addMethodName("setEndDate");

Let us see an example that explains the usage of NameMatchMethodPointcut.

The target class on which the advice is applied is shown as follows:

package org.springaop.chapter.two.pointcut;
public class NameMethodTargetExample {
public void printName(){
System.out.println("Max");
}
public void printAction(){
System.out.println("runs");
}
public void printSpot(){
System.out.println("in Poetto beach");
}
}

The advice that contains the logic to be executed:

package org.springaop.chapter.two.pointcut;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AdviceExample implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Invoking " + invocation.getMethod().getName());
Object retVal = invocation.proceed();
System.out.println("Job Done");
return retVal;
}
}

The test class:

package org.springaop.chapter.two.pointcut;
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 NameMethodMatcherExample {
public static void main(String[] args) {
NameMethodTargetExample target = new NameMethodTargetExample();
NameMatchMethodPointcut pc = new NameMatchMethodPointcut();
pc.addMethodName("printSpot");
pc.addMethodName("printAction");
Advisor advisor = new DefaultPointcutAdvisor(pc, new AdviceExample());
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
NameMethodTargetExample proxy = (NameMethodTargetExample)pf.getProxy();
proxy.printName();
proxy.printAction();
proxy.printSpot();
}
}

The result will be:

NameMatchMethodPointcut

Let's try to see what happened. We defined a target class, an around advice that prints, before the invocation, the name of the invoked method. Subsequently, the method invokes on the target class, and after the invocation it prints Job Done.

To test NameMethodMatcher, we'll write the NameMethodMatcherExample class with a main method, then add to NameMatchMethodPointcut only two of the three methods that could be matched by the pointcut.

Then we'll create an advisor that binds pointcut and advice, create a new ProxyFactory to which we will set advisor and target object, and then invoke methods.

The result is that only the two added methods (printAction() and printSpot()) are intercepted by the pointcut, whereas printName() is not intercepted.

RegexpMethodPointcut

To allow pointcuts in a more generic modality than the mere declaration of names, it's possible to use regular expressions.

For this purpose in Spring 1.x, Jakarta ORO (Perl5 regexp) is being used. If we want to use JDK 1.3; otherwise, we can use the regular expression provided by java.util.regex if running on JDK 1.4

The full qualified name is:

org.springframework.aop.support.JdkRegexpMethodPointcut

The JdkRexepMethodPointcut allows you to define pointcuts using JDK 1.4 regular expression support.

org.springframework.aop.support.Perl5RegexpMethodPointcut

The Perl5RegexpMethodPointcut allows you to define pointcuts using Perl 5 regular expression syntax.

For their configuration, we use a single pattern or a list of patterns:

  1. 1 patterns: Array of regular expressions for methods that the pointcut will match
  2. 2 pattern: Convenient String property when you have just a single pattern and don't need an array

In Spring 2.5, we have only the JdkRegexpMethodPointcut, for JDK 1.4 or higher.

<bean id="settersAndHumorousPointcut"
class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*get.*</value>
<value>.*humorous</value>
</list>
</property>
</bean>

If we use Spring 2.5 or 3.x and a JDK previous to 1.4, Jakarta ORO is used in the background, configuring an advisor in this way:

<bean id="settersAndHumorousAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="beanNameOfAopAllianceInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*humorous</value>
</list>
</property>
</bean>

An example of RegexpMethodPointcut use follows:

The target class on which to apply the advice:

package org.springaop.chapter.two.pointcut;
public class RegExpTargetExample {
public void printName(){
System.out.println("Max");
}
public void printAction(){
System.out.println("swims");
}
public void printSpot(){
System.out.println("in Poetto beach");
}
}

The advice that contains the logic to be executed:

package org.springaop.chapter.two.pointcut;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AdviceExample implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Invoking " + invocation.getMethod().getName());
Object retVal = invocation.proceed();
System.out.println("Job Done");
return retVal;
}
}

The test class:

package org.springaop.chapter.two.pointcut;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
public class RegExpMethodMatcherExample {
public static void main(String[] args) {
RegExpTargetExample target = new RegExpTargetExample();
JdkRegexpMethodPointcut pc = new JdkRegexpMethodPointcut();
String[] patterns = {".*Spot.*",".*Action.*"};
pc.setPatterns(patterns);
Advisor advisor = new DefaultPointcutAdvisor(pc, new AdviceExample());
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
RegExpTargetExample proxy = (RegExpTargetExample)pf.getProxy();
proxy.printName();
proxy.printAction();
proxy.printSpot();
}
}

The result will be:

RegexpMethodPointcut

Let's see what we have done. We defined a target class and an around advice that prints, before the invocation, the name of the invoked method. Subsequently, the method invokes on the target class, and after the invocation it prints Job Done. To test JdkRegexpMethodPointcut we wrote the RegExpMethodMatcherExample class with a main method. We set a string array with the patterns of regular expressions to JdkRegexpMethodPointcut.

We created an advisor that bound pointcut and advice, created a new ProxyFactory to which we set the advisor and target object. Then, we invoked methods.

The result was that only methods that contain the regular expressions in their name were intercepted by the pointcut.

StaticMethodMatcherPointcut

The StaticMethodMatcherPointcut abstract class is intended as a base for building static pointcuts.

The full qualified name of the class is:

org.springframework.aop.StaticMethodMatcherPointcut

We can use it as an anonymous inner class implementing the body of the method matches:

public static Pointcut exampleStaticPointcut = new StaticMethodMatcherPointcut() {
public boolean matches(Method m, Class targetClass) {
// implement custom check
}
};

Or extending it and implementing its methods:

public class StaticPointcutFooExample extends StaticMethodMatcherPointcut {
public boolean matches(Method method, Class clazz) {
return ("example".equals(method.getName()));
}
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class clazz) {
return (clazz == MyTarget.class);
}
};
}
}

This is an of example class to which apply advices:

package org.springaop.chapter.two.pointcut;
public class PointcutTargetExample {
public void printName(){
System.out.println("Max");
}
public void printSpot(){
System.out.println("in Poetto beach");
}
}

This is a second class of example to which apply advices:

package org.springaop.chapter.two.pointcut;
public class PointcutTargetExampleTwo {
public void printAction(){
System.out.println("swim");
}
public void printSpot (){
System.out.println("on Mediterranean Sea");
}
}

This is the StaticPointcutMatcher method. It represents the class in which we set out the matching rules on the type of class and on the method.

package org.springaop.chapter.two.pointcut;
import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
public class StaticPointcutMatcher extends StaticMethodMatcherPointcut {
public boolean matches(Method method, Class cls) {
return ("printSpot".equals(method.getName()));
}
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class cls) {
return (cls == PointcutTargetExample.class);
}
};
}
}

This is the advice. It represents the advice applied according to the StaticMethodMatcher.

package org.springaop.chapter.two.pointcut;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AdviceExample implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Invoking " + invocation.getMethod().getName());
Object retVal = invocation.proceed();
System.out.println("Job Done");
return retVal;
}
}

This is the test class:

package org.springaop.chapter.two.pointcut;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class StaticPointcutExample {
public static void main(String[] args) {
PointcutTargetExample one = new PointcutTargetExample();
PointcutTargetExampleTwo two = new PointcutTargetExampleTwo();
PointcutTargetExample proxyOne;
PointcutTargetExampleTwo proxyTwo;
Pointcut pc = new StaticPointcutMatcher();
Advice advice = new AdviceExample();
Advisor advisor = new DefaultPointcutAdvisor(pc, advice);
ProxyFactory pf = new ProxyFactory();
pf.addAdvisor(advisor);
pf.setTarget(one);
proxyOne = (PointcutTargetExample)pf.getProxy();
pf = new ProxyFactory();
pf.addAdvisor(advisor);
pf.setTarget(two);
proxyTwo = (PointcutTargetExampleTwo)pf.getProxy();
proxyOne.printName();
proxyTwo.printAction();
proxyOne.printSpot();
proxyTwo.printSpot();
}
}

The result will be:

StaticMethodMatcherPointcut

Let's try to see what has been done. We defined two target classes, PointcutTargetExample and PointcutTargetExampleTwo (they print some text), and a StaticPointcutMatcher, which is an around advice that prints, before the invocation, the name of the invoked method. Subsequently, the method invokes on the target class, and after the invocation it prints Job Done.

To test StaticPointcutMatcher, we wrote the StaticPointcutExample class with a main method.

Then we create an advisor that bound pointcut and advice, and created a new ProxyFactory to which we set advisor and target objects. Then, we invoked methods.

The result was that only the methods of the class that satisfied StaticPointcutMatcher were intercepted.

DynamicMethodMatcherPointcut

DynamicMethodMatcherPointcut is intended as a base class to build dynamic pointcuts.

The full qualified name is:

org.springframework.aop.support .DynamicMethodMatcherPointcut

The utilization is not so different from that of StaticMethodMatcherPointcut as the anonymous inner class:

public static Pointcut DynamicPointcutExample = new DynamicMethodMatcherPointcut() {
public boolean matches(Method m, Class targetClass) {
// implement custom check
}
public boolean matches(Method m, Class targetClass, Object[] args) {
// implement custom check
}
}

As explained at the beginning of this chapter, the method matches with two arguments. It is called like staticMethodMatcher, and if it returns true, the matches are recalled at every invocation with three arguments.

Here is an example of its use:

This is the class to which advices are applied:

package org.springaop.chapter.two.pointcut;
public class DynamicPointcutTargetExample {
public void setSpot(String spot){
this.spot = spot;
}
public void printSpot(){
System.out.println(spot);
}
private String spot;
}

As DynamicMethodMatcher, we use a class that executes the static match (matches(Method method, Class cls)) on the SetSpot method, and the dynamic one (matches(Method method, Class cls, Object[] args)) on parameters ending with "Ocean".

package org.springaop.chapter.two.pointcut;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.DynamicMethodMatcherPointcut;
public class DynamicMethodMatcher extends DynamicMethodMatcherPointcut {
public boolean matches(Method method, Class cls) {
System.out.println("Static check for " + method.getName());
return ("setSpot".equals(method.getName()));
}
public boolean matches(Method method, Class cls, Object[] args) {
System.out.println("Dynamic check for " + method.getName());
String spot = ((String) args[0]);
return spot.endsWith("Ocean");
}
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class cls) {
return (cls == DynamicPointcutTargetExample.class);
}
};
}
}

As advice we use the same class used in the StaticMethodMatcher's example:

package org.springaop.chapter.two.pointcut;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AdviceExample implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Invoking " + invocation.getMethod().getName());
Object retVal = invocation.proceed();
System.out.println("Job Done");
return retVal;
}
}

This is the test class:

package org.springaop.chapter.two.pointcut;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class DynamicPointcutExample {
public static void main(String[] args) {
DynamicPointcutTargetExample target = new DynamicPointcutTargetExample();
Advisor advisor = new DefaultPointcutAdvisor(
new DynamicMethodMatcher(), new AdviceExample());
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
DyinamicPointcutTargetExample proxy = ( DynamicPointcutTargetExample)pf.getProxy();
proxy.setSpot("Pacific Ocean");
proxy.setSpot("Mediterranean Sea");
proxy.setSpot("Atlantic Ocean");
proxy.printSpot();
proxy.printSpot();
proxy.printSpot();
}
}

The result will be:

DynamicMethodMatcherPointcut

Let's see what has been done. We defined a target class (DynamicPointcutTargetExample), a DynamicPointcutMatcher with the definition of the class and of the method valid for the match, an around advice that prints the name of the invoked method before the invocation. Subsequently, the method is invoked on the target class, and after the invocation, it prints Job Done.

To test DynamicPointcutMatcher, we wrote the DynamicPointcutExample class with a main method.

Then we created an advisor that bound pointcuts and advices. We also created a new ProxyFactory to which we set advisors and target objects. Then, we invoked methods.

The result was that at the first invocation, a static check was done on methods called from the proxy (the first four static checks). Then only when the static check was satisfied, the dynamic check was called to verify if we should apply advice.

主站蜘蛛池模板: 略阳县| 盈江县| 鄂托克前旗| 祁门县| 沂源县| 杭州市| 汤原县| 兴城市| 行唐县| 都安| 军事| 临沧市| 龙海市| 渑池县| 得荣县| 镇坪县| 永宁县| 时尚| 望都县| 大理市| 江城| 西昌市| 恩施市| 长子县| 客服| 新建县| 鹰潭市| 渭南市| 铜陵市| 个旧市| 环江| 滦南县| 永嘉县| 万年县| 新民市| 修文县| 锡林浩特市| 仲巴县| 宁城县| 佳木斯市| 安远县|