1. 前置准备
xml配置如下
//.....
<bean id="logUtil" class="com.songbl.aop.xml.util.LogUtil"></bean>
<aop:config>
<aop:aspect ref="logUtil">
<aop:pointcut id="myPoint" expression="execution( Integer com.songbl.aop.xml.service.MyCalculator.* (..))"/>
<aop:around method="around" pointcut-ref="myPoint"></aop:around>
<aop:before method="start" pointcut-ref="myPoint"></aop:before>
<aop:after method="logFinally" pointcut-ref="myPoint"></aop:after>
</aop:aspect>
</aop:config>
装载配置: Module spring-aop
中 resources->META-INF->spring.handlers
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
2. 解析xml配置文件
处理上文中的配置文件,大概流程如下:
->parseBeanDefinitions(...)
->parseCustomElement(ele)
-> this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)
//根据标签获取处理器
->handler.parse(...)
//处理器找到对应的解析器开始解析
3. 开始解析aop标签
ConfigBeanDefinitionParser.java
->parse()
public BeanDefinition parse(Element element, ParserContext parserContext) {
//......
// 注册自动代理模式创建器,AspectjAwareAdvisorAutoProxyCreator
//使用AopConfigUtils ,将beanDefiniton放到容器中;在bpp中实例化
//org.springframework.aop.config.internalAutoProxyCreator"
configureAutoProxyCreator(parserContext, element);
// 解析aop:config子节点下的aop:pointcut/aop:advice/aop:aspect
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) { // aspect 节点下不同的字节点。<pointCut
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) { //advisor
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) { //aspect
parseAspect(elt, parserContext);
}
}
//....
}
解析:configureAutoProxyCreator(parserContext, element)
将“org.springframework.aop.config.internalAutoProxyCreator” 字符串对应的AspectJAwareAdvisorAutoProxyCreator
类注册到Bean工厂中,待到bpp中实例化
public static void registerAspectJAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 将“org.springframework.aop.config.internalAutoProxyCreator”对应的class类为`AspectJAwareAdvisorAutoProxyCreator`注册到bean工厂中
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 如果指定proxy-target-class=true,则使用CGLIB代理,否则使用JDK代理
// 其实其为AspectJAwareAdvisorAutoProxyCreator类的proxyTargetClass属性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册到spring的bean工厂中,再次校验是否已注册
registerComponentIfNecessary(beanDefinition, parserContext);
}
对于解析<aop:aspect ref=“”>,调用arseAspect(elt, parserContext)
private void parseAspect(Element aspectElement, ParserContext parserContext) {
//....
// 解析其下的advice节点。主要是哪几个method ,前\后\环绕\返回、异常..
NodeList nodeList = aspectElement.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
//是否为advice:before/advice:after/advice:after-returning/advice:after-throwing/advice:around节点
if (isAdviceNode(node, parserContext)) {
// 校验aop:aspect必须有ref属性,否则无法对切入点进行观察操作
if (!adviceFoundAlready) {
adviceFoundAlready = true;
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect ....",
aspectElement, this.parseState.snapshot());
return;
}
beanReferences.add(new RuntimeBeanReference(aspectName));
}
// 解析advice节点并注册到bean工厂中
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
//.....
// 解析aop:point-cut节点并注册到bean工厂.aspect标签 下面
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {
parsePointcut(pointcutElement, parserContext);
}
}
-------->parseAdvice(....)
private AbstractBeanDefinition parseAdvice(...) {
try {
//....
// create the method factory bean
// 解析advice节点中的"method"属性(前、后、环绕、返回、异常),并包装为MethodLocatingFactoryBean对象
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
// 关联aspectName,包装为SimpleBeanFactoryAwareAspectInstanceFactory对象
RootBeanDefinition aspectFactoryDef =new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// 涉及point-cut属性的解析
//并结合上述的两个bean(定义信息),包装成adviceDefinition(还是beanDefinition)
//改定义信息中包含的构造函数是按照索引位置设置的,共3个参数
AbstractBeanDefinition adviceDef = createAdviceDefinition(
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,beanDefinitions, beanReferences);
// configure the advisor
// 最终包装为AspectJPointcutAdvisor对象。
// 设置这个名字,这个在循环里面,所以bd中是#0 #1....
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
//创建advisor的bean定义信息
//需要的参数是上面封装的adviceDef(bean定义信息)。嵌里面有3个参数的bd
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
//...
// 注册到工厂
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
//...
}
所以解析完的整体结果构造是
其它几个(XXXAdvice
)类似.