当前位置: 代码迷 >> .NET Framework >> Spring Framework源码(6):Spring AOP之解析标签
  详细解决方案

Spring Framework源码(6):Spring AOP之解析标签

热度:63   发布时间:2016-05-01 23:27:45.0
Spring Framework源码(六):Spring AOP之解析标签

     首先看下spring framework配置例子:

<aop:config> <aop:aspect id="myaop" ref="log"> <aop:pointcut id="mycut" expression="execution(* cn.itcast.service..*.*(..))"/> <aop:before pointcut-ref="mycut" method="doAccessCheck"/> <aop:after-returning pointcut-ref="mycut" method="doReturnCheck "/> <aop:after-throwing pointcut-ref="mycut" method="doExceptionAction"/> <aop:after pointcut-ref="mycut" method=“doReleaseAction"/> <aop:around pointcut-ref="mycut" method="doBasicProfiling"/> </aop:aspect></aop:config>

    服务器的servlet容器在加载web.xml文件启动后,会使用一个org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader类来读取applicationContext.xml文件,当解析aop标签时它会调用BeanDefinitionParserDelegate实例的parseCustomElement方法解析,这个代理类会寻找aop namespace中的handler即AopNamespaceHandler类并调用其resolve方法返回NamespaceHandler实例(这个过程中如果handlerMapping中没有这个handler则会调用AopNameSpaceHandler的init方法).

    我们来看下AopNamespaceHandler的初始化过程:

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());	}

    我们看到这里分别注册了<aop:config></aop:config>、<aop:aspectj-autoproxy></aop:aspectj-autoproxy>和<aop:scoped-proxy></aop:scoped-proxy>等主要标签的解析器。

    这里仅仅介绍Spring AOP(不解释Spring对AspectJ的支持),所以我们接下来看下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;	}

    ConfigBeanDefinitionParser类的成员函数:

     该方法第一步调用了configureAutoProxyCreator(parserContext, element)方法来注册一个AspectJAwareAdvisorAutoProxyCreator类型的bean。这个bean实现了BeanPostProcessor的子接口InstanitiationAwareBeanPostProcessor。实现方法如下图所示:

	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {		Object cacheKey = getCacheKey(beanClass, beanName);		if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {			if (this.advisedBeans.containsKey(cacheKey)) {				return null;			}			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {				this.advisedBeans.put(cacheKey, Boolean.FALSE);				return null;			}		}		if (beanName != null) {			TargetSource targetSource = getCustomTargetSource(beanClass, beanName);			if (targetSource != null) {				this.targetSourcedBeans.add(beanName);				Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);				Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);				this.proxyTypes.put(cacheKey, proxy.getClass());				return proxy;			}		}		return null;	}

      它会在每次初始化bean时使用getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource)方法获取所有和bean相关联的advisor,并根据配置文件中advisor相关的配置选择能使用的advisor。接下来调用createProxy(beanClass, beanName, specificInterceptors)来创建代理(AOP使用代理模式来织入代码)。完成代理的创建后,AOP会根据配置文件中的节点类型来解析标签。这里分别会解析三种类型的标签:Pointcut、Advisor、Aspect。我们这里以Advisor为例看下标签的解析过程。

private void parseAdvisor(Element advisorElement, ParserContext parserContext) {		AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);		String id = advisorElement.getAttribute(ID);		try {			this.parseState.push(new AdvisorEntry(id));			String advisorBeanName = id;			if (StringUtils.hasText(advisorBeanName)) {				parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);			}			else {				advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);			}			Object pointcut = parsePointcutProperty(advisorElement, parserContext);			if (pointcut instanceof BeanDefinition) {				advisorDef.getPropertyValues().add(POINTCUT, pointcut);				parserContext.registerComponent(						new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));			}			else if (pointcut instanceof String) {				advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));				parserContext.registerComponent(						new AdvisorComponentDefinition(advisorBeanName, advisorDef));			}		}		finally {			this.parseState.pop();		}	}

    这里解析了advisor标签的pointcut属性,并生成了一个DefaultBeanFactoryPointcutAdvisor的advisor并注册到parserContext中。

    总结一下Spring AOP的实现原理大致是:配置一个实现了InstantiationAwareBeanPostProcessor接口的bean,根据配置文件中关于Advisor和Pointcut的配置找到所有Advisor在bean初始化时根据需要为其生成代理。并在生成代理的过程中把advice织入在代理对象里。

  相关解决方案