Spring读源码系列之AOP--02---aop基本概念扫盲---下
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列之AOP--02---aop基本概念扫盲---下相关的知识,希望对你有一定的参考价值。
Spring读源码系列之AOP--02---aop基本概念扫盲---下
- 引子
- Advisor
- PointcutAdvisor:和切点有关的Advisor
- IntroductionAdvisor:引介切面
- IntroductionInfo:引介信息
- IntroductionAdvisor小结
引子
上一篇文章主要对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生成代理对象的终极奥义