Aop源码解析(一)BeanDefinition的准备工作

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-aopresources->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)类似.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值