文章预览
<aop:advisor>:
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
<aop:advisor advice-ref="adviceHandler" pointcut-ref="pointCut"/>
</aop:config>
<aop:aspect>:
<aop:config>
<aop:aspect id="aspect" ref="adviceHandler">
<aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
<aop:around method="doAround" pointcut-ref="pointCut"/>
</aop:aspect>
</aop:config>
1. 从配置文件上看
<aop:advisor>直接通过advice-ref和pointcut-ref指向advice和point。
<aop:aspect>需要在内部定义不同的advice类型,比如<aop:around>(注意<aop:pointcut>也可写到<aop:aspect>外部)
2. 从代码编写上看
这部分主要是Advice的编写
因为<aop:aspect>内部指定了Advice的类型,所以adviceHandler的实现类不需要实现任何借口,直接定义方法就行。
public class AdviceHandler {
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("-----doAround().invoke-----");
//调用核心逻辑
Object retVal = pjp.proceed();
System.out.println("-----End of doAround()------");
return retVal;
}
}
而<aop:advisor>对应的Advice实现就需要实现Advice接口,比如MethodBeforeAdvice。
public class AdviceHandler implements MethodBeforeAdvice, AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(" 此处可以做类似于Before Advice的事情");
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(" 此处可以做类似于After Advice的事情");
}
}
3. 从Spring解析过程来看
Spring AOP(3)
里面已经针对<aop:aspect>的实现做了粗略代码分析,这里就再好好分析一下。
核心代码就是parseCustomElement --> AopNamespaceHandler --> 加载ConfigBeanDefinitionParser --> parse()
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
//核心代码,注册org.springframework.aop.config.internalAutoProxyCreator这个BeanDefinition,
// 实例是AspectJAwareAdvisorAutoProxyCreator
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
//解析PointCut
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
//解析Advisor
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
//解析Aspect
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
(1) parsePointcut
针对<aop:pointcut>标签,解析创建并注册AspectJExpressionPointcut类型的BeanDefinition到BeanFactory。
代码如下:
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
//拿到PointCut的id
String id = pointcutElement.getAttribute(ID);
//拿到PointCut配置的expression
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
//创建pointCut的BeanDefinition
pointcutDefinition = createPointcutDefinition(expression);
//给BeanDefinition设置source
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
//如果设置了pointCut的ID,就把ID作为beanName,注册该BeanDefinition
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
//如果没有ID,就需要生成一个beanName
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}
return pointcutDefinition;
}
//创建AspectJExpressionPointcut类型的BeanDefinition,并且将expression作为property
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;
}
从下面截图就能看出,通过beanName "pointCut"就能拿到BeanDefinition,且有一个property "expression"。
<aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
(2) parseAdvisor
创建
DefaultBeanFactoryPointcutAdvisor
类型的BeanDefinition,并设置pointCut和advice作为property。
注意这里如果是advice-ref或者point-ref那么通过RuntimeBeanNameReference包装,然后作为Advisor的property。
如果是pointCut,那么就直接创建pointCut的BeanDefinition,然后作为Advisor的property。
这里的不同点,在populateBean()的时候,会有区别。
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
//创建DefaultBeanFactoryPointcutAdvisor类型的BeanDefinition
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
String id = advisorElement.getAttribute(ID);
try {
this.parseState.push(new AdvisorEntry(id));
String advisorBeanName = id;
if (StringUtils.hasText(advisorBeanName)) {
//根据advisor的id作为beanName注册DefaultBeanFactoryPointcutAdvisor类型的BeanDefinition
parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
}
else {
//如果没有ID,就生成一个beanName
advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
}
//拿到pointCut的BeanDefinition或者pointCut-ref的reference
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
//如果是BeanDefinition,就直接将pointcut作为property加到Advisor的BeanDefinition
if (pointcut instanceof BeanDefinition) {
advisorDef.getPropertyValues().add(POINTCUT, pointcut);
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
}
//如果是reference,就组装为RuntimeBeanReference作为property加到Advisor的BeanDefinition
else if (pointcut instanceof String) {
advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef));
}
}
finally {
this.parseState.pop();
}
}
//创建Advisor的BeanDefinition,并组装Advice
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
//创建DefaultBeanFactoryPointcutAdvisor类型的BeanDefinition
RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(advisorElement));
//拿到advice-ref,即切面advice的引用
String adviceRef = advisorElement.getAttribute(ADVICE_REF);
if (!StringUtils.hasText(adviceRef)) {
parserContext.getReaderContext().error(
"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
}
else {
//将advice引用对应的bean作为property加入Advisor的BeanDefinition里
advisorDefinition.getPropertyValues().add(
ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
}
//如果配置了order属性,同样将order加入Advisor的BeanDefinition
if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
}
return advisorDefinition;
}
//解析Advisor相关的pointCut属性
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,就跟parsePointcut逻辑一样,创建并注册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,就直接返回这个reference
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;
}
}
从下面图中可以看出DefaultBeanFactoryPointcutAdvisor还是比较直观好理解的,Advisor需要两个ref(advice和pointCut),作为property。
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
<aop:advisor advice-ref="adviceHandler" pointcut-ref="pointCut"/>
</aop:config>
DefaultBeanFactoryPointcutAdvisor
(3) parseAspect
<aop:aspect>包含的item比较多,需要根据Advice的类型去创建BeanDefinition,以及PointCut的BeanDefinition,最后将Advice的BeanDefinition加入Advisor的BeanDefinition的构造函数中,那么在创建Advisor的时候,会通过autowireConstructor()来实例化Advice。
private void parseAspect(Element aspectElement, ParserContext parserContext) {
//拿到appect的id
String aspectId = aspectElement.getAttribute(ID);
//拿到appect的name
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
//定义BeanDefinition的集合
List<BeanDefinition> beanDefinitions = new ArrayList<>();
//定义BeanReference的集合
List<BeanReference> beanReferences = new ArrayList<>();
//获取<aop:declare-parents>的配置
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
//创建DeclareParentsAdvisor类型的BeanDefinition,
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.
//开始解析Advice,即<aop:before>, <aop:after>, <aop:around>等标签
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
//判断是不是before, after, around, after-returning, after-throwing
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
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的BeanDefinition
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);
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
//调用parsePointcut解析<aop:pointcut>,创建AspectJExpressionPointcut BeanDefinition
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
//<aop:around method="doAround" pointcut-ref="pointCut"/>
//根据这个配置解析method以及pointcut-ref
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
//注册MethodLocatingFactoryBean的BeanDefinition,设置targetBeanName和methodName
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
//创建SimpleBeanFactoryAwareAspectInstanceFactory的BeanDefinition,设置aspectBeanName
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// register the pointcut
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// configure the advisor
// 上面创建玩Advice的BeanDefinition,接着创建AspectJPointcutAdvisor advisor的BeanDefinition
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
// 将Advice的BeanDefinition,作为Advisor BeanDefinition的构造函数参数
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
//创建AspectJAroundAdvice类型的BeanDefinition,并且将method-ref和pointcut-ref添加到该BeanDefinition的构造函数中
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
//根据before, after, around, after-returning, after-throwing,不同的Advice类型,返回不同的Advice类
//比如AspectJAroundAdvice, AspectJMethodBeforeAdvice
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
//设置Advice BeanDefinition的aspectName以及order属性
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
//如果存在returning, throwing, arg-names等attribute,添加到Advice BeanDefinition的属性上
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(
RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(
THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(
ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
//解析pointCut的属性,与parseAdvisor里面调用的方法一样
//区别就是这里不仅仅初始化PointCut的BeanDefinition,还会将methodDef, pointcut, aspectFactoryDef放入Advice BeanDefinition的构造函数
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
//如果pointcut是BeanDefinition类型就直接设置到Advice BeanDefinition的构造函数
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
//如果pointcut是String类型,即pointcut-ref,就封装RuntimeBeanReference设置到Advice BeanDefinition的构造函数
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
AspectJPointcutAdvisor比DefaultBeanFactoryPointcutAdvisor复杂很多
。
<aop:aspect id="aspect" ref="adviceHandler">
<aop:pointcut id="pointCut" expression="execution(* com.gary.spring.Student.*(..)) "/>
<aop:around method="doAround" pointcut-ref="pointCut"/>
</aop:aspect>
通过beanName "org.springframework.aop.aspectj.AspectJPointcutAdvisor#0"就能拿到BeanDefinition,且有一个构造函数 "AbstractAspectJAdvice"。
//构造函数,所以AspectJPointcutAdvisor需要通过构造函数注入Advice
public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
this.pointcut = advice.buildSafePointcut();
}
再点进去查看AspectJAroundAdvice的BeanDefinition,它存在三个构造函数参数,和两个property。
AspectJAroundAdvice
的三个构造参数分别注入的是MethodLocationFactoryBean,PointCut,SimpleBeanFactoryAwareAspectInstanceFactory。
-
MethodLocationFactoryBean 有两个property:targetBeanName和methodName,表示通知类advice的通知方法。
且它是一个FactoryBean,getObject()方法直接返回method,方便AspectJAroundAdvice拦截的时候通过method反射调用通知方法。
@Override
public void setBeanFactory(BeanFactory beanFactory) {
if (!StringUtils.hasText(this.targetBeanName)) {
throw new IllegalArgumentException("Property 'targetBeanName' is required");
}
if (!StringUtils.hasText(this.methodName)) {
throw new IllegalArgumentException("Property 'methodName' is required");
}
//从BeanFactory中获取beanClass
Class<?> beanClass = beanFactory.getType(this.targetBeanName);
if (beanClass == null) {
throw new IllegalArgumentException("Can't determine type of bean with name '" + this.targetBeanName + "'");
}
//通过反射拿到method
this.method = BeanUtils.resolveSignature(this.methodName, beanClass);
if (this.method == null) {
throw new IllegalArgumentException("Unable to locate method [" + this.methodName +
"] on bean [" + this.targetBeanName + "]");
}
}
//FactoryBean在实例化之后会调用getObject(),那么MethodLocationFactoryBean实例化最终返回的是method
public Method getObject() throws Exception {
return this.method;
}
MethodLocationFactoryBean
-
pointCut
因为本例中使用pointCut,所以这里pointCut是RuntimeBeanReference,在注入的时候会去注入pointCut对应的Bean。
-
SimpleBeanFactoryAwareAspectInstanceFactory
这是个工厂类,可以根据aspectBeanName去获取对应的bean。
在本例中,adviceHandler是在AspectJAroundAdvice被invoke调用时,通过该Factory来实例化bean的。
//AspectJAroundAdvice拦截器被调用
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
public Object getAspectInstance() {
Assert.state(this.beanFactory != null, "No BeanFactory set");
Assert.state(this.aspectBeanName != null, "No 'aspectBeanName' set");
return this.beanFactory.getBean(this.aspectBeanName);
}
SimpleBeanFactoryAwareAspectInstanceFactory
………………………………