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