首先看下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织入在代理对象里。