7.SpringAop之声明式Aop基于配置:AspectJAw
介绍
AspectJ项目是对java语言面向切面编程的一个扩展,Spring框架实现了AspectJ的部分功能。AspectJ最大的特点就是,对连接点的配置采用了AspectJ的表达式,在Spring框架中实现的最常用的表达式是execution表达式。
翻阅了一下aspectj文档,发现aspectj的示例代码全是Scala 的。根据spring框架的底层架构,估计也只能实现这部分。对于java语言而言,说不定都能实现。具体aspectj其他的有用的表达式可以去,aspectj的官网看看。对于我们日常编程而言,spring实现的也够用了。或者,我们可以转战Scala。
AspectJ基于xml配置的aop生效通过AspectJAwareAdvisorAutoProxyCreator这个类,下面我们来仔细分析下这个类
类继承结构

可以看到它继承了AbstractAdivisorAutoProxyCreator,也就是说子类只需要关注如何取到有效的Adivisor即可
使用
在讲解源码前,先介绍一下使用,对于xml模式,我们需要增加对应的xml配置如下
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* *.hello(..))"/>
<aop:pointcut id="pointcut2" expression="execution(* *.hello(..))"/>
<aop:aspect ref="testAspect" >
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
<!--测试基于注解的切面 -->
<aop:aspect ref="testAspect">
<aop:before method="before" pointcut-ref="pointcut2"/>
<aop:after method="after" pointcut-ref="pointcut2"/>
</aop:aspect>
</aop:config>
其中testAspect的before和after方法对应切面增强逻辑,在spring配置文件中增加了上述配置后,对应pointcut匹配的方法就会增加对应的增强逻辑
生成Advisor
AspectJAwareAdvisorAutoProxyCreator内的逻辑并不复杂,主要逻辑在如何通过xml配置生成对应的Advisor BeanDefinition到spring容器中去
首先我们要通过自定义的spring handler处理aop命名空间的xml配置,在spring-aop-*.jar的META-INF/spring.handlers文件中配置
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
看下AopNamespaceHandler的实现
public class AopNamespaceHandler extends NamespaceHandlerSupport {
/**
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*/
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
这边我们只需要关注config的ConfigBeanDefinitionParser
先看下BeanDefinitionParser接口定义
public interface BeanDefinitionParser {
/**
* Parse the specified {@link Element} and register the resulting
* {@link BeanDefinition BeanDefinition(s)} with the
* {@link org.springframework.beans.factory.xml.ParserContext#getRegistry() BeanDefinitionRegistry}
* embedded in the supplied {@link ParserContext}.
* <p>Implementations must return the primary {@link BeanDefinition} that results
* from the parse if they will ever be used in a nested fashion (for example as
* an inner tag in a {@code <property/>} tag). Implementations may return
* {@code null} if they will <strong>not</strong> be used in a nested fashion.
* @param element the element that is to be parsed into one or more {@link BeanDefinition BeanDefinitions}
* @param parserContext the object encapsulating the current state of the parsing process;
* provides access to a {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
* @return the primary {@link BeanDefinition}
*/
BeanDefinition parse(Element element, ParserContext parserContext);
}
主要就是一个解析方法,把xml对应的element解析为BeanDefinition
那么从ConfigBeanDefinitionParser的parse方法分析起来
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
通过上面代码,可以发现,aop:config元素有三种子节点,pointcut,adivisor以及aspect,分别对应切入点,通知器以及切面。advisor是spring内部自定义类型,也是我们需要产生的类型,pointcut和aspect其实也是用来生成adivsor的
同时我们也注意到configureAutoProxyCreator(parserContext, element);
这句代码会给我们在spring容器加入AspectJAwareAdvisorAutoProxyCreator的beandefinition,也就是说用aop:config后,我们不用在配置文件增加AspectJAwareAdvisorAutoProxyCreator的bean配置
下面分别介绍advisor,ponitcut,aspect的解析逻辑
advisor元素解析
首先看下advisor在xsd中的规则
xsd规范
<xsd:complexType name="advisorType">
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="advice-ref" type="xsd:string" use="required">
</xsd:attribute>
<xsd:attribute name="pointcut" type="xsd:string">
</xsd:attribute>
<xsd:attribute name="pointcut-ref" type="pointcutRefType">
</xsd:attribute>
<xsd:attribute name="order" type="xsd:token">
</xsd:attribute>
</xsd:complexType>
<xsd:simpleType name="pointcutRefType">
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
为了方便查看结构,我删除了<xsd:annotation>标签,这个标签相当于注释
同时我们可以发现,<aop:adivisor> 可以包括id,advice-ref,pointcut,pointcut-ref,order这些属性,没有子元素
解析逻辑
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
//创建Adivisor的BeanDefinition
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
String id = advisorElement.getAttribute(ID);
try {
this.parseState.push(new AdvisorEntry(id));
String advisorBeanName = id;
//将advisorDef预先放入BeanFactory,如果没有id,生成默认名字
if (StringUtils.hasText(advisorBeanName)) {
parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
}
else {
advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
}
//解析pointcut相关属性
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
//如果配置了pointcut属性,会在parsePointcutProperty方法解析为BeanDefinition
if (pointcut instanceof BeanDefinition) {
advisorDef.getPropertyValues().add(POINTCUT, pointcut);
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
}
//如果配置了pointcut-ref属性,对advisorDef增加RuntimeBeanReference即可
else if (pointcut instanceof String) {
advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef));
}
}
finally {
this.parseState.pop();
}
}
在方法的开始会创建DefaultBeanFactoryPointcutAdvisor类型的RootBeanDefinition,DefaultBeanFactoryPointcutAdvisor类这个Advisor类的不同之处在于如果没有配置advice,它会根据advice-ref从beanfactory获取,在现在的场景下,advice就是没有设置的,所有advice实现都会根据advice-ref从beanfactory获取。详细实现,大家可以自己看下源码。
如上所述,在createAdvisorBeanDefinition会设置advice-ref和order两个属性
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
//创建DefaultBeanFactoryPointcutAdvisor类型的RootBeanDefinition
RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(advisorElement));
//设置adviceRef属性,advice-ref必须配置
String adviceRef = advisorElement.getAttribute(ADVICE_REF);
if (!StringUtils.hasText(adviceRef)) {
parserContext.getReaderContext().error(
"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
}
else {
advisorDefinition.getPropertyValues().add(
ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
}
//设置order属性
if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
}
return advisorDefinition;
}
之后会根据pointcut和pointcut-ref属性对DefaultBeanFactoryPointcutAdvisor进行配置,逻辑在parsePointcutProperty方法
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
//pointcut和pointcut-ref只能配置一个
if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
parserContext.getReaderContext().error(
"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
//如果配置了pointcut,pointcut内的内容对应aspectj表达式,需要新建pointcut的BeanDefinition
else if (element.hasAttribute(POINTCUT)) {
// Create a pointcut for the anonymous pc and register it.
String expression = element.getAttribute(POINTCUT);
AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(element));
return pointcutDefinition;
}
//如果配置了pointcut-ref,直接返回内容,会在外层创建RuntimeBeanReference属性
else if (element.hasAttribute(POINTCUT_REF)) {
String pointcutRef = element.getAttribute(POINTCUT_REF);
if (!StringUtils.hasText(pointcutRef)) {
parserContext.getReaderContext().error(
"'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
return null;
}
return pointcutRef;
}
else {
parserContext.getReaderContext().error(
"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
}
创建pointcut类型的BeanDefinition的方法createPointcutDefinition在下节pointcut元素解析讲
在上述代码中我们可以发现 parserContext.registerComponent这个逻辑,这部分的代码是为了在该元素完成解析的时候做事件通知所用,不影响我们往BeanFactory放BeanDefinition的逻辑,所以请忽略。
ponitcut元素解析
xsd规范
<xsd:complexType name="pointcutType">
<xsd:attribute name="id" type="xsd:string" use="required">
</xsd:attribute>
<xsd:attribute name="expression" use="required" type="xsd:string">
</xsd:attribute>
</xsd:complexType>
pointcut标签很简单,就id和expression两个属性,解析逻辑也不复杂
解析逻辑
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
String id = pointcutElement.getAttribute(ID);
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
//根据expression创建切入点
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
//注册到BeanFactory
if (StringUtils.hasText(pointcutBeanName)) {
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}
return pointcutDefinition;
}
主要逻辑在createPointcutDefinition这个创建BeanDefinition方法上
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add(EXPRESSION, expression);
return beanDefinition;
}
注意到创建了AspectJExpressionPointcut类型的RootBeanDefinition,同时scope为prototype,因为这种类型的BeanDefinition会存在很多个吧,只是表达式不一样
一路看一下来都很简单,但是这个AspectJExpressionPointcut不简单,它的功能是根据配置的表达式去匹配连接点,也就是我们的方法。我们只要知道它功能即可,想看懂还真不容易。
aspect元素解析
xsd规范
<xsd:complexType name="aspectType">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="pointcut" type="pointcutType">
</xsd:element>
<xsd:element name="declare-parents" type="declareParentsType">
</xsd:element>
<xsd:element name="before" type="basicAdviceType">
</xsd:element>
<xsd:element name="after" type="basicAdviceType">
</xsd:element>
<xsd:element name="after-returning" type="afterReturningAdviceType">
</xsd:element>
<xsd:element name="after-throwing" type="afterThrowingAdviceType">
</xsd:element>
<xsd:element name="around" type="basicAdviceType">
</xsd:element>
</xsd:choice>
<xsd:attribute name="id" type="xsd:string">
</xsd:attribute>
<xsd:attribute name="ref" type="xsd:string">
</xsd:attribute>
<xsd:attribute name="order" type="xsd:token">
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="basicAdviceType">
<xsd:attribute name="pointcut" type="xsd:string">
</xsd:attribute>
<xsd:attribute name="pointcut-ref" type="pointcutRefType">
</xsd:attribute>
<xsd:attribute name="method" type="xsd:string" use="required">
</xsd:attribute>
<xsd:attribute name="arg-names" type="xsd:string">
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="afterReturningAdviceType">
<xsd:complexContent>
<xsd:extension base="basicAdviceType">
<xsd:attribute name="returning" type="xsd:string">
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="afterThrowingAdviceType">
<xsd:complexContent>
<xsd:extension base="basicAdviceType">
<xsd:attribute name="throwing" type="xsd:string">
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
可以从上面的xsd规范中看到,一个aspect标签有id,ref,order三个属性,可以包含一个或多个ponitcut以及5种advice的子元素。declare-parents目前不知道干嘛用
解析逻辑
private void parseAspect(Element aspectElement, ParserContext parserContext) {
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
List<BeanReference> beanReferences = new ArrayList<BeanReference>();
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
// We have to parse "advice" and all the advice kinds in one loop, to get the
// ordering semantics right.
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
//aspect标签的ref属性需要配置,因为advice方法是从ref对应的对象中获取,如果子元素存在advice配置,aspect没有配置ref,那么报错
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectElement, this.parseState.snapshot());
return;
}
beanReferences.add(new RuntimeBeanReference(aspectName));
}
//每个advice都会生成一个advisorDefinition
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
//获取子元素中的pointcut标签并且解析
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
//逻辑和解析pointcut标签一致
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
针对一个Aspect,里面可能会存在多个advice,在spring框架里面会对应生成多个Adivisor,然后在对目标方法切入的时候,这些adivisior会生成拦截器链
下面看下怎么把advice转换成Adivisor的BeanDefinition
private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// create the method factory bean
// methodDefinition对应的MethodLocatingFactoryBean用来获取aspect对应方法的Method对象
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
// create instance factory definition
// 用来从spring容器获取对应aspect对象
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// register the pointcut
// 通过上面2个BeanDefinition生成adviceDef对应的BeanDefinition
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// configure the advisor
// 创建advisorDefinition,设置advice属性
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
// 把BeanDefinition放入到Beanfactory
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
上面的方法会生成我们需要的Adivisor的BeanDefinition并且放入到Beanfactory,创建Advice BeanDefinition在createAdviceDefinition方法中
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
//getAdviceClass方法用于获取advice的class
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
//设置aspectname属性
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
//设置order属性
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
//设置returning属性
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(
RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
//设置throwing属性
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(
THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
//设置arg-names属性
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(
ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
//下面的逻辑是通过构造函数初始化Advice类
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
//构造函数第一个参数,advice对应aspect中的Method方法
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
// 构造函数的第二个方法,配置的切面,支持pointcut-ref和pointcut
// 配置advice的pointcut逻辑和解析pointcut标签一致
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
// 构造函数第三个参数,用于获取aspect对象
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
逻辑还是一顿疯狂的属性配置,在我们简单使用的背后,spring做了这么多事情,真是感动。
到这里所有的配置都解析完成了,由于没有看到配置lazyinit,所以在创建代理的时候,这些advisor BeanDefinition会被初始化成对象放入BeanFactory中,接下来就讲解这些adivisor如何生效
AspectJAwareAdvisorAutoProxyCreator对Adivisor的处理
AspectJAwareAdvisorAutoProxyCreator继承AbstractAdvisorAutoProxyCreator,主要重载了AspectJAwareAdvisorAutoProxyCreator的sortAdvisors,extendAdvisors,shouldSkip方法
关于AbstractAdvisorAutoProxyCreator介绍可以看我之前的文章
我们分别来看下这三个方法做了什么事情
shouldSkip
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor) {
//用于跳过Aspect类,Aspect类的方法不需要被切
if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
return true;
}
}
}
return super.shouldSkip(beanClass, beanName);
}
这个方法用于过滤哪些bean不需要生成代理,在上面的逻辑排除了Aspect配置类
extendAdvisors
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as
// this might eagerly instantiate a non-singleton AspectJ aspect
// 判断advisors中是否存在AspectJ类型的Adivisor
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
}
}
//如果存在AspectJ的Aop配置,会在advisors数组头插入ExposeInvocationInterceptor
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
extendAdvisors用来对得到adivisor进行扩展,这边会判断当前的Aop配置中是否存在AspectJ类型的配置,判断逻辑如下
private static boolean isAspectJAdvice(Advisor advisor) {
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
(advisor instanceof PointcutAdvisor &&
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
如果存在的话,会在adivisor数组加入ExposeInvocationInterceptor.ADVISOR,
同时ExposeInvocationInterceptor的优先级order是最高的
@Override
public int getOrder() {
return PriorityOrdered.HIGHEST_PRECEDENCE + 1;
}
也就是拦截器链第一位会执行
注意一点,优先级order不代表数字最大,因为优先级最高,第一个被执行,那么对应排序要在第一位,所以数字需要越小越好,所以 PriorityOrdered.HIGHEST_PRECEDENCE对应
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
ExposeInvocationInterceptor.ADVISOR对应的逻辑
这个类的invoke逻辑如下
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
其中invocation是ThreadLocal类型,这个adivisor的具体作用是可以让其他的aspectj类型的adivisor可以获取到当前的调用链路,因为adivisor的advice全是用代理生成的,只能通过JointPoint来获取调用链路
sortAdvisors
sortAdvisors会在extendAdvisors后执行
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
用来对Advisor进行排序,生成拦截器链,排在前面的会先调用
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors =
new ArrayList<PartiallyComparableAdvisorHolder>(advisors.size());
for (Advisor element : advisors) {
partiallyComparableAdvisors.add(
new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
}
List<PartiallyComparableAdvisorHolder> sorted =
PartialOrder.sort(partiallyComparableAdvisors);
if (sorted != null) {
List<Advisor> result = new ArrayList<Advisor>(advisors.size());
for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
result.add(pcAdvisor.getAdvisor());
}
return result;
}
else {
return super.sortAdvisors(advisors);
}
}
会通过PartiallyComparableAdvisorHolder包装Advisor,然后提供DEFAULT_PRECEDENCE_COMPARATOR的对比器
private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();
通过这个对比器进行排序,排序好之后,再把advisor提取出来返回
内部代码不分析了,直接说下排序的算法
简单一句话,after类型的advice order越大优先级越高,其他的是order越小,优先级越高
最后
希望大家关注下我的公众号,我保证自己每天都能更新(有点难),为了我的粉丝哈
