Spring读源码系列之AOP--02---aop基本概念扫盲---下

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列之AOP--02---aop基本概念扫盲---下相关的知识,希望对你有一定的参考价值。

Spring读源码系列之AOP--02---aop基本概念扫盲---下


引子

上一篇文章主要对Pointcut,Advice和Joinpoint做了分析,详情看下面这篇文章:

Spring读源码系列之AOP–01—aop基本概念扫盲—上

本文主要针对AOP最后一块盲区进行讲解,即Advisor,然后再讲解一下Spring如何整合这些组件的


Advisor

Advisor是Spring AOP的顶层抽象,用来管理Advice和Pointcut(PointcutAdvisor和切点有关,但IntroductionAdvisor和切点无关)

注意:Advice是aopalliance对通知(增强器)的顶层抽象,请注意区分~~

Pointcut是Spring AOP对切点的抽象。切点的实现方式有多种,其中一种就是AspectJ

public interface Advisor 

	//@since 5.0 Spring5以后才有的  空通知  一般当作默认值
	Advice EMPTY_ADVICE = new Advice() ;
	
	// 该Advisor 持有的通知器
	Advice getAdvice();
	// 这个有点意思:Spring所有的实现类都是return true(官方说暂时还没有应用到)
	// 注意:生成的Advisor是单例还是多例不由isPerInstance()的返回结果决定,而由自己在定义bean的时候控制
	// 理解:和类共享(per-class)或基于实例(per-instance)相关  类共享:类比静态变量   实例共享:类比实例变量
	boolean isPerInstance();


它的继承体系主要有如下两个:PointcutAdvisor和IntroductionAdvisor


IntroductionAdvisor与PointcutAdvisor最本质上的区别就是,IntroductionAdvisor只能应用于类级别的拦截,只能使用Introduction型的Advice。

而不能像PointcutAdvisor那样,可以使用任何类型的Pointcut,以及几乎任何类型的Advice。


PointcutAdvisor:和切点有关的Advisor

PointcutAdvisor它的实现类非常的多:

public interface PointcutAdvisor extends Advisor 
	Pointcut getPointcut();


AbstractPointcutAdvisor:抽象实现—可设置优先级

// 实现了 Ordered接口
public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable 
	// 调用者可以手动来指定Order
	public void setOrder(int order) 
		this.order = order;
	
	
	@Override
	public int getOrder() 
		if (this.order != null) 
			return this.order;
		
		
		// 若调用者没有指定Order,那就拿advice的order为准(若有),否则LOWEST_PRECEDENCE表示最后执行
		Advice advice = getAdvice();
		if (advice instanceof Ordered) 
			return ((Ordered) advice).getOrder();
		
		return Ordered.LOWEST_PRECEDENCE;
	
	// Spring还没有使用该属性 永远返回true了
	@Override
	public boolean isPerInstance() 
		return true;
	
	...



AbstractGenericPointcutAdvisor 一般的、通用的PointcutAdvisor—可配置advice

public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor 
	private Advice advice = EMPTY_ADVICE;
	public void setAdvice(Advice advice) 
		this.advice = advice;
	
	@Override
	public Advice getAdvice() 
		return this.advice;
	
	...



DefaultPointcutAdvisor 通用的,最强大的Advisor

它是Spring提供的通用的,也被认为是最强大的Advisor。它可以把任意的两个Advice和Pointcut放在一起,除了introductions类型的Advice

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable 

	private Pointcut pointcut = Pointcut.TRUE;

	public DefaultPointcutAdvisor() 
	

	public DefaultPointcutAdvisor(Advice advice) 
		this(Pointcut.TRUE, advice);
	

	public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) 
		this.pointcut = pointcut;
		setAdvice(advice);
	

	public void setPointcut(@Nullable Pointcut pointcut) 
		this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
	

	@Override
	public Pointcut getPointcut() 
		return this.pointcut;
	
	...


AbstractBeanFactoryPointcutAdvisor:和bean工厂有关的PointcutAdvisor

// 实现了BeanFactoryAware接口,若在Bean容器里注册可以注入BeanFactory~~~从而访问里面的实例
public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware 
	
	// 我们发现这两个都是@Nullable,所以他们脱离容器使用也是可以的
	@Nullable
	private String adviceBeanName;
	@Nullable
	private BeanFactory beanFactory;
	
	@Nullable
	private transient volatile Advice advice;
	
	public void setAdviceBeanName(@Nullable String adviceBeanName) 
		this.adviceBeanName = adviceBeanName;
	
	@Override
	public void setBeanFactory(BeanFactory beanFactory) 
		this.beanFactory = beanFactory;
		// 若在Spring环境下,会给AdviceMonitor重新赋值为:getSingletonMutex()
		resetAdviceMonitor();
	
	
	// 此处加锁
	public void setAdvice(Advice advice) 
		synchronized (this.adviceMonitor) 
			this.advice = advice;
		
	

	// 这是它最重要的方法,获取增强器
	@Override
	public Advice getAdvice() 
		Advice advice = this.advice;
		// 非Spring环境一般手动set进来,所以就直接返回吧
		if (advice != null) 
			return advice;
		

		//显然进来Spring容器环境了,bean工厂和beanName都是不能为null的
		Assert.state(this.adviceBeanName != null, "'adviceBeanName' must be specified");
		Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
		
		// 若bean是单例的  那就没什么好说的  直接去工厂里拿出来就完事了(Advice.class)  有可能返回null哦
		if (this.beanFactory.isSingleton(this.adviceBeanName)) 
			advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
			this.advice = advice;
			return advice;
		
		// 若是多例的,就加锁  然后调用getBean()给他生成一个新的实例即可
		else 
			synchronized (this.adviceMonitor) 
				//这步赋值和判断不能省~~~确保万无一失
				advice = this.advice;
				if (advice == null) 
					advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
					this.advice = advice;
				
				return advice;
			
		
	



DefaultBeanFactoryPointcutAdvisor:通用的BeanFactory的Advisor
public class DefaultBeanFactoryPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor 
	private Pointcut pointcut = Pointcut.TRUE;

	// 若传进来为null,还是选择 Pointcut.TRUE 匹配所有
	public void setPointcut(@Nullable Pointcut pointcut) 
		this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
	
	@Override
	public Pointcut getPointcut() 
		return this.pointcut;
	


在Spring事务相关里,你会看到这个类

位于org.springframework.aop.support包内


BeanFactoryCacheOperationSourceAdvisor:和Cache有关

Spring Cache的@Cachable等注解的拦截,就是采用了它。该类位于:org.springframework.cache.interceptor,显然它和cache相关了。Jar包属于:Spring-context.jar

// @since 3.1  毕竟Spring的整个org.springframework.cache.Cache体系都是从这里开始的。(@Cacheable...等等)
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor 

	// 显然它最重要的是持有这个引用,后面cache系列会详细讲解
	@Nullable
	private CacheOperationSource cacheOperationSource;

	// Pointcut使用的是CacheOperationSourcePointcut
	private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() 
		@Override
		@Nullable
		protected CacheOperationSource getCacheOperationSource() 
			return cacheOperationSource;
		
	;


	public void setCacheOperationSource(CacheOperationSource cacheOperationSource) 
		this.cacheOperationSource = cacheOperationSource;
	
	public void setClassFilter(ClassFilter classFilter) 
		this.pointcut.setClassFilter(classFilter);
	
	@Override
	public Pointcut getPointcut() 
		return this.pointcut;
	




AsyncAnnotationAdvisor:和@Async有关

位于包为:org.springframework.scheduling.annotation,所属jar包为spring-context.jar

public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware 
	// 处理异步发生的异常的====
	private AsyncUncaughtExceptionHandler exceptionHandler;
	
	private Advice advice;
	private Pointcut pointcut;

	// 构造函数们
	public AsyncAnnotationAdvisor() 
		this(null, null);
	
	// executor:可以自己指定异步任务的执行器
	// exceptionHandler:异步异常的处理器
	public AsyncAnnotationAdvisor(@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) 
		Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
		asyncAnnotationTypes.add(Async.class);
		
		// 支持EJB的注解:@Asynchronous
		try 
			asyncAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
		 catch (ClassNotFoundException ex) 
			// If EJB 3.1 API not present, simply ignore.
		
		if (exceptionHandler != null) 
			this.exceptionHandler = exceptionHandler;
		 else 
			// SimpleAsyncUncaughtExceptionHandler:只是一个简单的logger.error的输入打印
			this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
		
		
		// buildAdvice: new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler)   它是个MethodInterceptor  环绕通知器
		this.advice = buildAdvice(executor, this.exceptionHandler);
		// 把asyncAnnotationTypes交给buildPointcut,它最终是个ComposablePointcut,会把这两种注解都支持。union起来 或者的关系
		this.pointcut = buildPointcut(asyncAnnotationTypes);
	

	public void setTaskExecutor(Executor executor) 
		this.advice = buildAdvice(executor, this.exceptionHandler);
	
	...



AspectJPointcutAdvisor

AbstractAspectJAdvice的实现类如下:这5个实现类完完整整的对应着我们AspectJ的那5个注解。

AbstractAspectJAdvice内部维护了一个AspectJExpressionPointcut pointcut


显然是和AspectJ相关的,使用得很是广泛。注意它和AspectJExpressionPointcutAdvisor的区别。

有名字也能看出来,AspectJExpressionPointcutAdvisor和表达式语言的切点相关的,而AspectJPointcutAdvisor是无关的。它哥俩都位于包org.springframework.aop.aspectj里。

public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered 
	
	//AbstractAspectJAdvice通知:它的子类看下面截图,就非常清楚了
	private final AbstractAspectJAdvice advice;
	//可以接受任意的Pointcut,可谓非常的通用(当然也包含切点表达式啦)
	private final Pointcut pointcut;

	@Nullable
	private Integer order;
	
	//只有这一个构造函数,包装一个advice
	public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) 
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
		// 然后pointcut根据advice直接给生成了一个。这是AbstractAspectJAdvice#buildSafePointcut的方法
		this.pointcut = advice.buildSafePointcut();
	
...

	public final Pointcut buildSafePointcut() 
	//拿到AbstractAspectJAdvice内部维护的AspectJExpressionPointcut pointcut
		Pointcut pc = getPointcut();
		MethodMatcher safeMethodMatcher = MethodMatchers.intersection(
				new AdviceExcludingMethodMatcher(this.aspectJAdviceMethod), pc.getMethodMatcher());
		return new ComposablePointcut(pc.getClassFilter(), safeMethodMatcher);
	

InstantiationModelAwarePointcutAdvisor

它是PointcutAdvisor的一个子接口。

// 由SpringAOP顾问包装AspectJ实现的接口 可能具有延迟初始化策略的方面。
// 例如,一个PerThis实例化模型意味着对建议的初始化太慢
public interface InstantiationModelAwarePointcutAdvisor extends PointcutAdvisor 

	// 该Advisor是否需要懒加载
	boolean isLazy();
	// 判断此Advisor它所拥有的Advice是否已经初始化了
	boolean isAdviceInstantiated();


它的唯一实现类:InstantiationModelAwarePointcutAdvisorImpl

// 默认的访问权限,显然是Spring内部自己用的
class InstantiationModelAwarePointcutAdvisorImpl
		implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable 
	private static final Advice EMPTY_ADVICE = new Advice() ;
	// 和AspectJExpression
	private final AspectJExpressionPointcut declaredPointcut;
	..
	
	// 通知方法
	private transient Method aspectJAdviceMethod;
	
	private final AspectJAdvisorFactory aspectJAdvisorFactory;
	private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;

	@Nullable
	private Advice instantiatedAdvice;
	@Nullable
	private Boolean isBeforeAdvice;
	@Nullable
	private Boolean isAfterAdvice;
	
	...
	@Override
	public boolean isPerInstance() 
		return (getAspectMetadata().getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON);
	
	@Override
	public synchronized Advice getAdvice() 
	//第一次获取Adivce时,才去创建---懒加载
		if (this.instantiatedAdvice == null) 
			this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
		
		return this.instantiatedAdvice;
	
	
	// advice 由aspectJAdvisorFactory去生产  懒加载的效果
	private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) 
		Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
				this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
		return (advice != null ? advice : EMPTY_ADVICE);
	

	@Override
	public boolean isBeforeAdvice() 
		if (this.isBeforeAdvice == null) 
			determineAdviceType();
		
		return this.isBeforeAdvice;
	
	@Override
	public boolean isAfterAdvice() 
		if (this.isAfterAdvice == null) 
			determineAdviceType();
		
		return this.isAfterAdvice;
	
	
	// 这里解释根据@Aspect方法上标注的注解,来区分这两个字段的值的
	private void determineAdviceType() 
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(this.aspectJAdviceMethod);
		if (aspectJAnnotation == null) 
			this.isBeforeAdvice = false;
			this.isAfterAdvice = false;
		
		else 
			switch (aspectJAnnotation.getAnnotationType()) 
				case AtAfter:
				case AtAfterReturning:
				case AtAfterThrowing:
					this.isAfterAdvice = true;
					this.isBeforeAdvice = false;
					break;
				case AtAround:
				case AtPointcut:
					this.isAfterAdvice = false;
					this.isBeforeAdvice = false;
					break;
				case AtBefore:
					this.isAfterAdvice = false;
					this.isBeforeAdvice = true;
			
		
	
	...以上是关于Spring读源码系列之AOP--02---aop基本概念扫盲---下的主要内容,如果未能解决你的问题,请参考以下文章

Spring读源码系列之AOP--04---proxyFactory创建代理对象

Spring读源码系列之AOP--03---aop底层基础类学习

Spring读源码系列之AOP--08--aop执行完整源码流程之自动代理创建器导入的两种方式

Spring读源码系列之AOP--05---aop常用工具类学习

Spring读源码系列之AOP--07---aop自动代理创建器(拿下AOP的最后一击)

Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义