切入点

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_44778952/article/details/89468505

Pointcut接口

pointcut是切入点,是很多连接点的集合,目的是要找到合适的地方来应用通知。在Spring中目前只支持一种形式的连接点,也就是在调用public的非静态方法时,可以应用通知。
对于切入点来说,有两个方面需要确定。一个是到底应用到那些类上,第二个是能够应用到那些方法上面。从这个思路出发,Pointcut接口刚好提供了两个方法

  • ClassFilter getClassFilter()

    • ClassFilter
      • 专门用于检查目标类是否是一个合适的切入点
      • 方法 boolean matches(Class<?> clazz)
      • 常量 ClassFilter TRUE=TrueClassFilter.INSTANCE
  • MthodMather getMthodMathcer()

    • MthodMather
      • 实例主要是检查方法是否合适以便应用切面
      • 方法 boolean isRuntime()
      • 方法 boolean matches(Method m,Class<?> targetClass)
      • 方法 boolean matches(Method m,Class<?> targetClass,Object[] args)
      • MethodMatcher接口的实现支持静态和动态两种类型,取决于在调用方法匹配判断之前调用的方法isRuntime的返回值
        • 如果返回的是true:动态,先调用一次matches(Method m,Class<?> targetClass)方法,若返回true,则后续调用matches(Method m,Class<?> targetClass,Object[] args)
          • 第一个matches方法返回true,后面的matches方法在每次调用匹配方法时都会调用一次,进行方法参数的匹配
        • 返回false:静态,只调用一次matches(Method m,Class<?> targetClass)方法

Spring在处理Pointcut匹配的时候,先调用的是getClassFilter方法检查目标类是否匹配,若返回true,再调用getMthodMather检查方法是否匹配

API层次

在这里插入图片描述
上图中,都是跟Pointcut接口相关的类,其中有一个抽象的StaticMthodMatcherPointcut类(静态的),还有一个抽象的DynamicMethodMatcherPointcut类(动态的)。

StaticMethodMatcherPointcut

示例代码
接口

package com.csdn.springaop.target;

public interface MyInterface {
	public void method1();
	public void method2() throws Exception ;
}

目标类

package com.csdn.springaop.target;

public class Target implements MyInterface {
	public void method1() {
		System.out.println("Target method1");
	}
	public void method2() throws Exception {
		throw new Exception("Target method2 Error!");
	}
}

测试代码

package com.csdn.springaop.test;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import com.csdn.springaop.advice.MyAfterReturningAdvice;
import com.csdn.springaop.advice.MyAroundAdvice;
import com.csdn.springaop.advice.MyBeforeAdvice;
import com.csdn.springaop.advice.MyThrowsAdvice;
import com.csdn.springaop.target.MyInterface;
import com.csdn.springaop.target.Target;

public class SpringTest2 {
	@Test
	public  void test1() {
		Target target=new Target();
		MyBeforeAdvice myBeforeAdvice=new MyBeforeAdvice();
	
		ProxyFactory proxyFactory =new ProxyFactory();
		proxyFactory.setTarget(target);
		proxyFactory.addAdvice(myBeforeAdvice);

		MyInterface target1=(MyInterface)proxyFactory.getProxy();
		target1.method1();
		System.out.println("开始运行toString方法");
		target1.toString();
	}
}

上面运行结果

MyBeforeAdvice
Target method1
开始运行toString方法
MyBeforeAdvice

从结果中可以看到,调用代理目标类的toString方法也执行了Before通知,原因是我们调用ProxyFactory工厂的addAdvice方法,并没有限制那些方法能够应用到通知。
下面我们将测试代码修改下

@Test
	public  void test2() {
		Target target=new Target();
		MyBeforeAdvice myBeforeAdvice=new MyBeforeAdvice();
	
		ProxyFactory proxyFactory =new ProxyFactory();
		proxyFactory.setTarget(target);
		
		Pointcut pointcut=new StaticMethodMatcherPointcut() {

			@Override
			public boolean matches(Method method, Class<?> targetClass) {
				return "method1".equals(method.getName());
			}
			
		};
		DefaultPointcutAdvisor advisor=new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
	 
		proxyFactory.addAdvisor(advisor);
		
		MyInterface target1=(MyInterface)proxyFactory.getProxy();
	 
		target1.method1();
		System.out.println("开始运行toString方法");
		target1.toString();
		 
	}

原来的测试代码中,向代理工厂中加入了通知后,并没有限定应用通知的方法,所以我们加入了一个特定的切入点,这个切入点能够限定到底哪个类的哪些方法能够引用到通知。根据AOP的核心概念,这已经组合成了一个切面,我们已经可以使用下面的接口

  • Advisor接口
    • 表示切面,有两个子接口
      • PointcutAdvisor
        • 基于切入点的
        • DefaultPointcutAdvisor是PointcutAdvisor的默认实现
      • IntroductionAdvisor
        • 跟引入相关的

输出结果

MyBeforeAdvice
Target method1
开始运行toString方法

可以看到,只有method1方法应用到通知了。

DynamicMethodMatcherPointcut

上面应用到一个静态MethodMatcher的抽象类,下面再应用一个动态的MthodMatcher的抽象类,并重写其带有三个参数的matches方法

@Test
	public  void test3() {
		Target target=new Target();
		MyBeforeAdvice myBeforeAdvice=new MyBeforeAdvice();
	
		ProxyFactory proxyFactory =new ProxyFactory();
		proxyFactory.setTarget(target);
		
		Pointcut pointcut=new DynamicMethodMatcherPointcut() {
			
			@Override
			public boolean matches(Method method, Class<?> targetClass, Object... args) {
				return "method1".equals(method.getName())&&args.length==1&&args[0].equals("one");
			}
		};
		DefaultPointcutAdvisor advisor=new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
	 
		proxyFactory.addAdvisor(advisor);
		
		MyInterface target1=(MyInterface)proxyFactory.getProxy();
	 
		System.out.println("运行method()");
		target1.method1();
		System.out.println("运行method(\"one\")");
		target1.method1("one");
		System.out.println("运行method(\"two\")");
		target1.method1("two");
		 
	}

在目标中重载一个method1方法

public void method1(String s) {
		System.out.println("Target method1"+s);
}

上面运行结果

运行method()
Target method1
运行method("one")
MyBeforeAdvice
Target method1one
运行method("two")
Target method1two

可以看出,只有method1方法,并且调用时参数是“one”的情况应用到了通知。

DefaultPointcutAdvisor

构造方法

  • public DefaultPointcutAdvisor()
  • public DefaultPointcutAdvisor(Advice advice)
  • public DefaultPointcutAdvisor(Pointcut pointcut,Advice advice)

普通方法

  • setPointcut(Pointcut pointcut)
  • setAdvice(Advice advice)
  • setOrder(int order)

猜你喜欢

转载自blog.csdn.net/weixin_44778952/article/details/89468505