spring源码分享之Aop系列四(advisor,pointcut和targetSource)_isadviceinstantiated-程序员宅基地

技术标签: spring  aop  spring学习笔记  

前面介绍了advice以及adivce是怎么进入到目标的调用链中进行调用的,不过在spring中advice都是包在advisor中进行注册的,而pointcut则是切面,主要用来匹配对应的方法是否需要进行Advice增强,而targetSource则是代理的目标源,这个源可以是单例,实例池等。

Advisor

可以看到Advisor的下层主要是两个子接口IntrodutionAdvisorPointcutAdvisor以及一个PrototypePlaceholderAdvisor
这个ProtoTypePlaceHolderAdvisor中没有advice,只是维护了一个beanName以便ProxyFactoryBean在获取prototype类型的代理类时能从容器中获取对应的Advisor

Advisor其下的一种是IntroductionAdvisor一种是PointcutAdvisor
对于IntroductionAdvisor一个是所有的都匹配都过的DefaultIntrodcutionAdvisor,另一种主要是对 @DeclareParents 这个注解的实现。
另一种就是PointcutAdvisor,这个接口主要是利用Pointcut来过滤目标bean是否需要进行Advice的增强。

方式 advisor
<aop:advice/> AspectJPointcutAdvisor
<aop:advice><declare-parents/><aop:advice/> DeclareParentsAdvisor
<aop:advisor/> DefaultBeanFactoryPointcutAdvisor
@Before InstantiationModelAwarePointcutAdvisorImpl
@After InstantiationModelAwarePointcutAdvisorImpl
@AfterThrowing InstantiationModelAwarePointcutAdvisorImpl
@AfterReturning InstantiationModelAwarePointcutAdvisorImpl
@Around InstantiationModelAwarePointcutAdvisorImpl
@DeclareParents DeclareParentsAdvisor

在这里插入图片描述

public interface Advisor {
    
    //返回这个advisor中的advice
	Advice getAdvice();
	//是否和特定的实例关联,不过spring框架中没有对这个方法进行调用,所有的实现类都是返回true
	boolean isPerInstance();
}

IntroductionAdvisor

IntroductionAdvisor接口继承了AdvisorIntroductionInfo,这个IntroductionInfo则是提供描述一个introduction的详细信息,主要是其需要实现的接口。
IntroductionAdvisor主要有两个方法,一个是getClassFilter() 用于获取获取对应的类过滤器。另一个方法则是validateInterfaces() 用于验证其Advice能否对IntroductionInfo中需要实现的接口进行实现。

public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
    
    //返回类过滤器,检查对应的类是否需要应用这个advisor中的advice
	ClassFilter getClassFilter();
	//验证IntrodutionInfo中的interface能否应用到对应的advice中
	//这个在将IntroductionAdvisor加入到AdvisedSupport之前会调用
	void validateInterfaces() throws IllegalArgumentException;
}

DefaultIntroductionAdvisor

DefaultIntroductionAdvisor实现了三个接口IntroductionAdvisorClassFilterOrdered,其对ClassFilter中的实现为直接返回true,并且对IntroductionAdvisorgetClasFilter() 的实现是返回自己。表明它注入到容器中则会对所有的bean进行增强。

而其维护了一个set来存储注册到这个Advisor中需要实现的Interface。如果其advice实现了IntroductionInfo的接口则会从Advice中获取。

它还实现了Ordered接口,对于AbstractAdvisorAutoProxyCreator找到的对应的Advisor链最终会进行排序,而其默认是LOWEST_PRECEDENCE则默认是放在调用链的第一个。

public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFilter, Ordered, Serializable {
    

    //对应的advisor
	private final Advice advice;
	//对应需要实现的接口
	private final Set<Class<?>> interfaces = new LinkedHashSet<Class<?>>();
    //排序用的
	private int order = Ordered.LOWEST_PRECEDENCE;

	public DefaultIntroductionAdvisor(Advice advice) {
    
		this(advice, (advice instanceof IntroductionInfo ? (IntroductionInfo) advice : null));
	}

	public DefaultIntroductionAdvisor(Advice advice, IntroductionInfo introductionInfo) {
    
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
		if (introductionInfo != null) {
    
			Class<?>[] introducedInterfaces = introductionInfo.getInterfaces();
			if (introducedInterfaces.length == 0) {
    
				throw new IllegalArgumentException("IntroductionAdviceSupport implements no interfaces");
			}
			for (Class<?> ifc : introducedInterfaces) {
    
				addInterface(ifc);
			}
		}
	}

	public DefaultIntroductionAdvisor(DynamicIntroductionAdvice advice, Class<?> ifc) {
    
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
		addInterface(ifc);
	}

	public void addInterface(Class<?> ifc) {
    
		Assert.notNull(ifc, "Interface must not be null");
		if (!ifc.isInterface()) {
    
			throw new IllegalArgumentException("Specified class [" + ifc.getName() + "] must be an interface");
		}
		this.interfaces.add(ifc);
	}

	@Override
	public Class<?>[] getInterfaces() {
    
		return ClassUtils.toClassArray(this.interfaces);
	}

	@Override
	public void validateInterfaces() throws IllegalArgumentException {
    
		for (Class<?> ifc : this.interfaces) {
    
			if (this.advice instanceof DynamicIntroductionAdvice &&
					!((DynamicIntroductionAdvice) this.advice).implementsInterface(ifc)) {
    
				throw new IllegalArgumentException("DynamicIntroductionAdvice [" + this.advice + "] " +
						"does not implement interface [" + ifc.getName() + "] specified for introduction");
			}
		}
	}

	@Override
	public boolean matches(Class<?> clazz) {
    
		return true;
	}

   ...
}

DeclareParentsAdvisor

这个Advisor是注解**@DeclareParents最终注册的Advisor**,@DeclareParents配置中的valuedefaultImpl则为其构造函数中的typePatterndefaultImpl,而其对应的interfaceType则是其配置的Field的类型。

其·对应的advice是DelegatePerTargetObjectIntroductionInterceptorDelegatingIntroductionInterceptor两种,为IntroductionInterceptor的两种默认实现的advice。

public class DeclareParentsAdvisor implements IntroductionAdvisor {
    

	private final Advice advice;

	private final Class<?> introducedInterface;

	private final ClassFilter typePatternClassFilter;

	public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Class<?> defaultImpl) {
    
		this(interfaceType, typePattern,
				new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));
	}

	public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Object delegateRef) {
    
		this(interfaceType, typePattern, new DelegatingIntroductionInterceptor(delegateRef));
	}
	private DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, IntroductionInterceptor interceptor) {
    
		this.advice = interceptor;
		this.introducedInterface = interfaceType;

		// Excludes methods implemented.
		ClassFilter typePatternFilter = new TypePatternClassFilter(typePattern);
		ClassFilter exclusion = new ClassFilter() {
    
			@Override
			public boolean matches(Class<?> clazz) {
    
				return !introducedInterface.isAssignableFrom(clazz);
			}
		};
		this.typePatternClassFilter = ClassFilters.intersection(typePatternFilter, exclusion);
	}


	@Override
	public ClassFilter getClassFilter() {
    
		return this.typePatternClassFilter;
	}

	@Override
	public void validateInterfaces() throws IllegalArgumentException {
    
		// Do nothing
	}

	@Override
	public boolean isPerInstance() {
    
		return true;
	}

	@Override
	public Advice getAdvice() {
    
		return this.advice;
	}
	@Override
	public Class<?>[] getInterfaces() {
    
		return new Class<?>[] {
    this.introducedInterface};
	}

}

PointcutAdvisor

PointcutAdvisor继承了Advisor,并提供了一个getPointcut()获取Pointcut,而Pointcut这个接口中提供了获取ClassFilterMethodMatcher的方法,表明PointcutAdvisor是方法级别的,而上面的IntroductionAdvisor的粒度只能到类级别。

public interface PointcutAdvisor extends Advisor {
    
	Pointcut getPointcut();
}

PointcutAdvisor的子类主要是对于其AdvicePointcut的种类以及获取方式的不同而有了不同的实现,下图展示了其对应的抽象类和实现类的具体的功能。
在这里插入图片描述

InstantiationModelAwarePointcutAdvisor

除了上面的相关的实现外,PointcutAdvisor还有一个子接口,InstantiationModelAwarePointcutAdvisor,这个子接口有一个唯一的实现InstantiationModelAwarePointcutAdvisorImpl,它是通过注解形式注入的最终的Advisor,这个接口提供了懒加载Advice的策略,所以提供了是否是懒加载以及advice是否被实例化的方法。

public interface InstantiationModelAwarePointcutAdvisor extends PointcutAdvisor {
    
    //是否是懒加载
	boolean isLazy();
	//advice是否已经被实现了的
	boolean isAdviceInstantiated();
}
InstantiationModelAwarePointcutAdvisorImpl

这个实例不是由BeanFactory实现的,而是ReflectiveAspectJAdvisorFactory实现的。它主要实现了InstantiationModelAwarePointcutAdvisorAspectJPrecedenceInformation这两个接口,其中AspectJPrecedenceInformation主要是进行advisor排序时需要使用的接口,AbstractAspectJAdvice也实现了这个接口。

这个Advisor的对应的AdviceAspectJAdvisorFactory 进行实现的,其PointcutPerTargetInstantiationModelPointcut ,这个Pointcut是一个动态的Pointcut,其主要作用是在aspectJInstance还没有实例化时利用perClausePointcut进行静态匹配。而在运行中再用定义好的AspectJExpressionPointcut进行匹配。

class InstantiationModelAwarePointcutAdvisorImpl
		implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {
    
    //声明的pointcut
	private final AspectJExpressionPointcut declaredPointcut;
    //用于序列化获取对应的方法
	private final Class<?> declaringClass;
    //用于序列化后获取对应的Method对象
	private final String methodName;
    //用于序列化后获取对应的Method对象
	private final Class<?>[] parameterTypes;
    //对应的aspectJAdviceMethod
	private transient Method aspectJAdviceMethod;
    //利用这个factory创建advice
	private final AspectJAdvisorFactory aspectJAdvisorFactory;
    //从这个factory中获取instance
	private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
    //用于advisor的比较
	private final int declarationOrder;
    //用于advisor的比较
	private final String aspectName;
    //最终是以的pointcut
	private final Pointcut pointcut;
    //对应的切面实例是否是懒加载
	private final boolean lazy;
    //实现出来的advice
	private Advice instantiatedAdvice;
    //是否是前置advice
	private Boolean isBeforeAdvice;
    //是否是后置advice
	private Boolean isAfterAdvice;
	public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    

		this.declaredPointcut = declaredPointcut;
		this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
		this.methodName = aspectJAdviceMethod.getName();
		this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
		this.aspectJAdviceMethod = aspectJAdviceMethod;
		this.aspectJAdvisorFactory = aspectJAdvisorFactory;
		this.aspectInstanceFactory = aspectInstanceFactory;
		this.declarationOrder = declarationOrder;
		this.aspectName = aspectName;

        //对于在Aspect对象是懒加的情况则加上在@Aspect中配置的表达式匹配
		if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
    
			Pointcut preInstantiationPointcut = Pointcuts.union(
					aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
			this.pointcut = new PerTargetInstantiationModelPointcut(
					this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
			this.lazy = true;
		}
		else {
    
			// A singleton aspect.
			this.pointcut = this.declaredPointcut;
			this.lazy = false;
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
	}
	@Override
	public synchronized Advice getAdvice() {
    
		if (this.instantiatedAdvice == null) {
    
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		}
		return this.instantiatedAdvice;
	}
    //利用aspectJAdvisorFactory实例化对应的Advice
	private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
    
		return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
	}

	private class PerTargetInstantiationModelPointcut extends DynamicMethodMatcherPointcut {
    

		private final AspectJExpressionPointcut declaredPointcut;

		private final Pointcut preInstantiationPointcut;

		private LazySingletonAspectInstanceFactoryDecorator aspectInstanceFactory;
		
		public PerTargetInstantiationModelPointcut(AspectJExpressionPointcut declaredPointcut,
				Pointcut preInstantiationPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    

			this.declaredPointcut = declaredPointcut;
			this.preInstantiationPointcut = preInstantiationPointcut;
			if (aspectInstanceFactory instanceof LazySingletonAspectInstanceFactoryDecorator) {
    
				this.aspectInstanceFactory = (LazySingletonAspectInstanceFactoryDecorator) aspectInstanceFactory;
			}
		}

        //静态匹配时在aspectJ还没有实例化时加上
        //利用@Aspect中prethis或者pretarget等配置的表达式以进行匹配,
		@Override
		public boolean matches(Method method, Class<?> targetClass) {
    
			return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass)) ||
					this.preInstantiationPointcut.getMethodMatcher().matches(method, targetClass);
		}
        //运行时匹配,需要对应的aspect实例化才能匹配成功。
		@Override
		public boolean matches(Method method, Class<?> targetClass, Object... args) {
    
			return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass));
		}

		private boolean isAspectMaterialized() {
    
			return (this.aspectInstanceFactory == null || this.aspectInstanceFactory.isMaterialized());
		}
	}

}

targetSource

targetSource是代理目标的获取源,spring实现了很多种类型的targetSource,其扩展的方式主要是获取的位置以及对应target的生命周期
在这里插入图片描述

targetSource接口

TargetSource 继承了TargetClassAware,Advised接口也实现了这个接口,不过其实现了AdvisedSupport类也是用其对应的targetSource获取对应的class。

public interface TargetSource extends TargetClassAware {
    
	//返回目标的class
	@Override
	Class<?> getTargetClass();
	//对应的target是否是否改变
	boolean isStatic();
	//获取target对象
	Object getTarget() throws Exception;
	//释放target对象
	void releaseTarget(Object target) throws Exception;
}

targetSource的子类

  • targetSource

    • AbstractBeanFactoryBasedTargetSource: 这个抽象类主要实现了BeanFactoryAware接口,并维护了beanFactory,它的target实例是从beanFactory获取。

      • AbstractPrototypeBasedTargetSource: 主要是验证了target的beanName对应的bean在beanFactory的类型是prototype。

        • AbstractPoolingTargetSource: 这个抽象类实现了PoolConfig,表示是池类的targetSource 。

          • CommonsPool2TargetSource: 利用apache的ObjectPool来存储对应的target对象,它实现了PooledObjectFactory,这个池中的对象还是从beanFactory中获取。
        • ProtoTypeTargetSource: 直接从beanFactory中获取prototype类型的bean作为target。

        • ThreadLocalTargetSource: 将获取的bean存储在ThreadLocal ,它在releaseTarget的操作的时候不会从ThreadLocal中释放对应的target。

      • LazyInitTargetSource: 在调用getTarget()方法时才从beanFactory中获取对应的bean存储在本地对象中。

      • SimpleBeanTargetSource: 直接从beanFactory中获取对应的bean作为target。

    • AbstractLazyCreationTargetSource: 在调用getTarget() 才调用其抽象方法createObject() 获取对应的target。

    • AbstractRefreshableTargetSource: 根据时间会刷新target。

      • BeanFactoryRefreshableTargetSource: 他的target是从beanFactory中获取。
    • EmptyTargetSource: 直接返回Null

    • HotswappableTargetSource: 提供一个**swap()**方法可以替换内部的target。

    • SingletonTargetSource: 内部维护了一个唯一的对象作为target。

Pointcut

Pointcut主要是用来匹配对应的切点,主要是提供了ClassFilterMethodMatcher两个匹配接口,分别对目标的以及方法进行匹配,其扩展主要是在方法的匹配上进行的,分别在运行时,静态。然后匹配的位置主要扩展方式是匹配注解调用栈,方法名等。而匹配的方式的扩展主要有利用正则 ,AspectJ表达式等进行匹配。
在这里插入图片描述

Pointcut接口

可以看到,Pointcut主要是提供了ClassFilterMethodMatcher两个匹配起,具体的匹配规则则委托给了这两个匹配器。

public interface Pointcut {
    
	ClassFilter getClassFilter();
	MethodMatcher getMethodMatcher();
	Pointcut TRUE = TruePointcut.INSTANCE;
}

Pointcut子类

  • Pointcut

    • AnnotationMatchingPointcut: 主要是匹配对应的class 和method的注解有没有配置的注解。

    • ComposablePointcut: 主要是可以和其他的ClassFilterMethodMatcher,pointcut或者的操作,将它们组合起一个ComposablePointcut操作。

    • ControlFlowPoint: 从调用栈中找对应的method的匹配(匹配的是类名和方法名)。

    • DynamicMethodMatcherPointcut: 继承了DynamicMethodMatcher,其ClassFilter直接为true

      • PerTargetInstantiationModelPointcut: 这个是InstantiationModelAwarePointcutAdvisorImpl 中用的pointcut,主要作用是在aspect实例懒加载时利用preInstantiationPointcut进行实现。先用preThis,pertarget等生命周期中的对应下的切面中配置的对应的表达式进行静态匹配。
    • StaticMethodMatcherPointcut: 继承了StaticMethodMatcher ,对应的ClassFiltertrue,只进行静态匹配对应的目标的method

    • AbstractRegxpMethodPointcut: 维护了匹配正则字符串数组和过滤正则字符串数组。

      • JdkRegxpMethodPointcut: 使用java正则的方式匹配对应的方法名。
    • GetterPointcut: 匹配对应的方法名是否是以get开头的。

    • NameMatchMethodPointcut: 使用*和.来匹配目标方法名。

    • SetterPointcut: 匹配对应的方法名是否是以set开头的。

    • StaticMethodPointcutAdvisor: 匹配静态方法的advisor的抽象类。

  • TruePointcut: calssFilter和MethodMatcher都返回true 。

  • ExpressionPointcut: 提供了一个**getExpression() **方法

  • AbstractExpressionPointcut: 维护了一个字符串的表达式

  • AspectJExpressionPointcut: 利用AspectJ表达式进行匹配。

AspectJExpressionPointcut

AspectJExpressionPointcut是用spring-aop常用的pointcut,在利用@Before,
<aop:advice/>等方式注入advisor时其pointcut都是AspectJExpressionPointcut
所以详细介绍一下这种pointcut。

AspectJExpressionPointcut的是将其对应的表达式转换为PointcutExpression,其对method的匹配结果为ShadowMatch,并利用shadowMatchCache 进行了缓存,而其对应的运行时的匹配则是利用ShadowMatch来进行匹配。

可以看到AspectJExpressionPointcut实现了ClassFilterIntroductionAwareMethodMatcher以及BeanFactoryAware 三个接口,可以看到其对应的MethodMatcherIntroductionAwareMethodMatcher,这个接口,这个接口定义了一个需要参数hasIntroductions表示其调用链中有没有IntroduceAdvice

public class AspectJExpressionPointcut extends AbstractExpressionPointcut
		implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
    
    //支持的语法
	private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();
	static {
    
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
	}
	// 对应的aspect的class
	private Class<?> pointcutDeclarationScope;
    //构建pointcutExpression的参数
	private String[] pointcutParameterNames = new String[0];
    //构建pointcutExpression的参数类型
	private Class<?>[] pointcutParameterTypes = new Class<?>[0];
	//beanFactory主要是
	private BeanFactory beanFactory;
    //用来构建pointcutClassLoader
	private transient ClassLoader pointcutClassLoader;
    //aspectJ中的匹配表达式,有点类似jdk中的Pattern
	private transient PointcutExpression pointcutExpression;
    //为每个method维护了一个ShadowMatch缓存,这个ShadowMatch有点类似jdk中的Matcher
	private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);

   ...

}
ClassFilter中的匹配

ClassFiltermatch方法实现匹配类。可以看到它是用PointcutExpression的借助couldMatchJoinPointsInType() 方法来进行匹配的,可以看到它在匹配出现ReflectionWorldException异常时会利用fallbackExpression来尝试匹配一次,这个fallbackExpression与原来的pointcutExpression不同之处在于它们的classLoader是不一样的,pointcutExpression默认用的是beanFactory的,而fallbackExpression则是用的pointcutDeclarationScope的classLoader。

@Override
	public boolean matches(Class<?> targetClass) {
    
		checkReadyToMatch();
		try {
    
			try {
    
				return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
			}
			catch (ReflectionWorldException ex) {
    
				logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
				
				PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
				if (fallbackExpression != null) {
    
					return fallbackExpression.couldMatchJoinPointsInType(targetClass);
				}
			}
		}
		catch (Throwable ex) {
    
			logger.debug("PointcutExpression matching rejected target class", ex);
		}
		return false;
	}
方法静态匹配

主要是获取对应的ShadowMatch来进行匹配,对于立刻能判断成功的直接返回判断结果,而对于target的instanceof这些表达式则可以直接判断,因为spring的targetClass在运行时是不会发生改变。

@Override
	public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
    
	    //实例化pointcutExpression
		checkReadyToMatch();
		//获取其目标方法,这个method对象的对应的class可能不是targetClass
		//尽可能找到目标class中这个method的对象
		Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
		//获取ShadowMatch
		ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
		if (shadowMatch.alwaysMatches()) {
    
			return true;
		}
		else if (shadowMatch.neverMatches()) {
    
			return false;
		}
		else {
    
			// the maybe case
			if (beanHasIntroductions) {
    
				return true;
			}
			RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
			//这里主要是测试表达式中instanceof这种判断,因为在spring-aop中的targetSource在运行时是不会发生改变,因此在静态匹配中就可以过滤掉那些表达式中instanceOf不匹配的target
			return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
		}
	}

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
    
		return matches(method, targetClass, false);
	}
方法动态匹配

方法动态的匹配主要是在运行时获取对应的this,targetargs对象进行匹配,而对thistarget对象的获取主要是依赖ExposeInvocationInterceptor这个advice将其ThreadLocal中进行获取。

@Override
	public boolean matches(Method method, Class<?> targetClass, Object... args) {
    
		checkReadyToMatch();
		ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
		ShadowMatch originalShadowMatch = getShadowMatch(method, method);
		ProxyMethodInvocation pmi = null;
		Object targetObject = null;
		Object thisObject = null;
		//从当前调用链中的暴露出来的代理对象获取this和target
		try {
    
			MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
			targetObject = mi.getThis();
			if (!(mi instanceof ProxyMethodInvocation)) {
    
				throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
			}
			pmi = (ProxyMethodInvocation) mi;
			thisObject = pmi.getProxy();
		}
		catch (IllegalStateException ex) {
    
			// No current invocation...
			if (logger.isDebugEnabled()) {
    
				logger.debug("Could not access current invocation - matching with limited context: " + ex);
			}
		}

		try {
    
		    //匹配this,target和args
			JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
			if (pmi != null) {
     
			    //匹配this的instanceof数据
				RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
				if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
    
					return false;
				}
				if (joinPointMatch.matches()) {
    
				    //将JoinPointMatch放入ProxyMethodInvocation的userAttributes中,对应的AbstractAspectJAdvice中的aspectJAdviceMethod的JoinPointMatch参数就是此处
					bindParameters(pmi, joinPointMatch);
				}
			}
            //返回运行时匹配的结果
			return joinPointMatch.matches();
		}
		catch (Throwable ex) {
    
			if (logger.isDebugEnabled()) {
    
				logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
						" - falling back to non-match", ex);
			}
			return false;
		}
	}
获取shadowMatch

获取shadowMatch主要是先利用targetMethod获取,如果其没有获取则利用originalMethod获取,但是最终存储到cache的key是targetMethod

private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
    
		ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
		if (shadowMatch == null) {
    
			synchronized (this.shadowMatchCache) {
    
				PointcutExpression fallbackExpression = null;
				Method methodToMatch = targetMethod;
				shadowMatch = this.shadowMatchCache.get(targetMethod);
				if (shadowMatch == null) {
    
					try {
    
						try {
    
							shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
						}
						catch (ReflectionWorldException ex) {
    
							try {
    
								fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
								if (fallbackExpression != null) {
    
									shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
								}
							}
							catch (ReflectionWorldException ex2) {
    
								fallbackExpression = null;
							}
						}
						if (shadowMatch == null && targetMethod != originalMethod) {
    
							methodToMatch = originalMethod;
							try {
    
								shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
							}
							catch (ReflectionWorldException ex3) {
    
								// Could neither introspect the target class nor the proxy class ->
								// let's try the original method's declaring class before we give up...
								try {
    
									fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
									if (fallbackExpression != null) {
    
										shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
									}
								}
								catch (ReflectionWorldException ex4) {
    
									fallbackExpression = null;
								}
							}
						}
					}
					catch (Throwable ex) {
    
						// Possibly AspectJ 1.8.10 encountering an invalid signature
						logger.debug("PointcutExpression matching rejected target method", ex);
						fallbackExpression = null;
					}
					if (shadowMatch == null) {
    
						shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
					}
					else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
    
						shadowMatch = new DefensiveShadowMatch(shadowMatch,
								fallbackExpression.matchesMethodExecution(methodToMatch));
					}
					this.shadowMatchCache.put(targetMethod, shadowMatch);
				}
			}
		}
		return shadowMatch;
	}

pointcut的配置

名称 配置类型 匹配类型
execution 方法表达式 匹配方法执行的连接点
this 类型全限定名 匹配当前的代理对象
target 类型全限定名 匹配目标对象
args 参数类型列表 匹配执行方法传入的参数的类型
within 类型表达式 匹配执行对应类型表达式下的方法
@target 注解类型 匹配目标是否有对应的注解
@within 注解类型 任何目标对象对应的类型是否有对应的注解
@args 注解列表 匹配执行方法传入的参数是否带有指定注解
@annotation 注解类型 匹配当前执行方法持有指定注解的方法
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cq_pf/article/details/107002566

智能推荐

稀疏编码的数学基础与理论分析-程序员宅基地

文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...

EasyGBS国标流媒体服务器GB28181国标方案安装使用文档-程序员宅基地

文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档

【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链_原生jackson 反序列化链子-程序员宅基地

文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子

一文搞懂SpringCloud,详解干货,做好笔记_spring cloud-程序员宅基地

文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud

Js实现图片点击切换与轮播-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换

tensorflow-gpu版本安装教程(过程详细)_tensorflow gpu版本安装-程序员宅基地

文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装

随便推点

物联网时代 权限滥用漏洞的攻击及防御-程序员宅基地

文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者

Visual Odometry and Depth Calculation--Epipolar Geometry--Direct Method--PnP_normalized plane coordinates-程序员宅基地

文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be ​ and th_normalized plane coordinates

开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先抽取关系)_语义角色增强的关系抽取-程序员宅基地

文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景​ 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取

10个顶尖响应式HTML5网页_html欢迎页面-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面

计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...-程序员宅基地

文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思

conan简单使用_apt install conan-程序员宅基地

文章浏览阅读240次。conan简单使用。_apt install conan