您的位置:首页 > 编程语言 > Java开发

Spring Aop技术原理分析

2014-04-01 16:02 344 查看
  本篇文章从Aop xml元素的解析开始,分析了Aop在Spring中所使用到的技术。包括Aop各元素在容器中的表示方式、Aop自动代理的技术、代理对象的生成及Aop拦截链的调用等等。将这些技术串联起来,就能勾勒出Aop在Spring中的使用脉络。

一、Spring Aop的解析

  在Spring xml配置中,不同的功能配置通过不同的命名空间引入,如事务方面的配置通过引入http://www.springframework.org/schema/tx命名空间来实现,而对Aop的配置则是引入http://www.springframework.org/schema/aop。对于引入的这些命名空间及其元素,Spring注册了不同的NamespaceHandler类型来处理,如Aop配置元素的解析就是通过AopNamespaceHandler来实现。在Spring中,各种NamespaceHandler的继承关系如下图所示:





以Aop配置信息为例,对于该命名空间各元素的解析主要是通过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 copedProxyBeanDefinitionDecorator());

// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}


如果在xml配置文件中配置了<aop:aspectj-autoproxy />元素,则是通过SpringConfiguredBeanDefinitionParser类来解析。Spring将所要用到的handler分别配置在jar包的META-INF/ spring.handlers文件中,spring-aop包中的文件信息如下:

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler


对spring.handlers文件的加载则是在DefaultNamespaceHandlerResolver中,

private Map<String, Object> getHandlerMappings() {
if (this.handlerMappings == null) {
synchronized (this) {
if (this.handlerMappings == null) {
try {
Properties mappings =PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
his.handlerMappings = handlerMappings;
}
catch (IOException ex) {
}
}
}
}
return this.handlerMappings;
}


其中handlerMappingsLocation为META-INF/spring.handlers。DefaultNamespaceHandlerResolver类存放在XmlReaderContext类中,由BeanDefinitionParserDelegate和BeanDefinitionParserDelegate调用,而这两个则在DefaultBeanDefinitionDocumentReader类中使用,最终由各种BeanFarctory(Spring容器)来调用。

二、注册AutoProxyCreator类

针对@AspectJ风格的AOP,Spring Aop提供了两个AutoProxyCreator实现类进行自动代理,分别是AspectJAwareAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator,对应于配置文件(<aop:config>)和使用注解的方式。在配置文件中加入<aop:aspect-autoproxy/>,spring会使用AnnotationAwareAspectJAutoProxyCreator,而加入<aop:config />则会使用AspectJAwareAdvisorAutoProxyCreator。在Spring内部,只会使用其中之一。如果两种方式都配置了,则会使用AnnotationAwareAspectJAutoProxyCreator(在spring内部注解方式的优先级更高),详情可以查看AopConfigUtils类。因为AnnotationAwareAspectJAutoProxyCreator继承于AspectJAwareAdvisorAutoProxyCreator ,在调用自己的处理逻辑之前,会调用父类的实现逻辑,所以前者兼容后者。

三、Aop代理对象的生成

通过配置文件(或注解)将Aop切面配置好之后,ConfigBeanDefinitionParser类会将pointcut,advisor和aspect解析生成BeanDefinition,并注册到相应的BeanFactory中,以便在AspectJAwareAdvisorAutoProxyCreator中使用,解析的代码如下:

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


每当读取到aop:config元素时,spring会将其子元素分别解析并注册到BeanFactory中。当调用getBean()时,BeanFactory会调用注册到容器中的BeanPostProcessor(AspectJAwareAdvisorAutoProxyCreator)对象,判断是否满足拦截请求,如果满足,则获取所有满足条件的Advisor,加入到ProxyFactory中,生成代理对象返回,其代码如下所示:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(bean.getClass(), beanName,
pecificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}

this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}


在BeanFactory生成Bean对象的时候,会对Bean对象进行一些初始化操作,1)判断是否继承aware接口,然后注入相应的aware对象;2)调用BeanPostProcessor类中的postProcessBeforeInitialization方法;3)判断是否继承InitializingBean,然后afterPropertiesSet方法;4),调用BeanPostProcessor类中的postProcessAfterInitialization方法。对代理对象的生成主要是在第2和第4步,其代码如下所示:

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
// step 1
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// step 2
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
// step 3
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}

if (mbd == null || !mbd.isSynthetic()) {
// step 4
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}


在Spring容器中有可能会注册多个BeanPostProcessor,执行第2和第4步时,它会返回第一个不为空的对象,这时起作用的只有一个BeanPostProcessor对象,所以在注册自动代理对象的时候要尤为注意,其代码如下所示:

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {

Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}


四、Aop拦截链的调用

在代理对象中,有可能会有多个Advisor对象与之匹配,这些Advisor会在最终目标对象执行之前,按照指定的顺序和优先级执行,顺序号决定优先级,顺序号越小,优先级越高,优先级排在前面的,将被优先执行。默认情况下,如果不明确指定各个Advisor的执行顺序,那么Spring会按照它们的声明顺序应用他们,最先声明的顺序号最小但优先级最大,其次将之。顺序号由Ordered指定,在BeanPostProcessor 各个子类中实现排序,如AspectJAwareAdvisorAutoProxyCreator中的sortAdvisors函数。

代理对象中会存有一个Advisor列表,以JdkDynamicAopProxy(CglibAopProxy类似)为例,它实现了InvocationHandler接口,并将自己传给了代理对象,在代理对象中会调用其invoke方法,在该方法中有一段关键代码:

// 得到这个方法的拦截器链
List<Object> chain =
this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

// 判断拦截器链是否为空,若为空,直接调用目标方法
if (chain.isEmpty()) {
// 直接调用目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// 调用拦截器链
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}


调用拦截器链的功能主要ReflectiveMethodInvocation类中的proceed方法来实现,代码如下所示:

public Object proceed() throws Throwable {
// 判断是否到了链尾,如果是则执行目标方法,调用结束。
if (this.currentInterceptorIndex ==
this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 取出当前的Advisor;
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 判断是否需要动态判断参数,如果需要则执行如下操作;
       // 参数验证通过则执行Advisor,否则跳过该Advisor;
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
// 如果不需要动态判断参数,则执行该Advisor,因为在之前已经验证通过了;
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}


在上面的代码中,好像并没有类似递归操作的语句(也没有循环语句)来执行拦截器链,那么代码是怎么执行多个Advisor的?Spring对三种Advisor(MethodBeforeAdvice,AfterReturningAdvice和ThrowsAdvice)采用了适配器方式,将它们转换为MethodInterceptor方法,如MethodBeforeAdviceAdapter实现如下:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}

public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}


MethodBeforeAdvice的语义是指在目标方法之前执行,在MethodBeforeAdviceInterceptor类按照其语义进行了转义,使得在ReflectiveMethodInvocation类中可以统一用invoke方法进行调用,其invoke方法代码如下所示:

public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}


对比BeforeAdvice的适配,现在应该可以想像AfterReturningAdvice的适配了,那就是先执行mi.proceed()方法,然后再执行advice的after方法,用代码来验证一下:

public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}


回到刚才的问题,代码是怎么完成递归操作的?看了代码,应该很清楚了。在MethodBeforeAdviceInterceptor的invoke方法中,有mi.proceed()这样的语句,而mi则是由ReflectiveMethodInvocation传入的this对象,即其自身对象。可以用如下的序列图来表示:





五、总结

用一句话来形容Aop,那就是proxy+Interceptors+target,即一个代理对象,多个拦截器再加目标对象的技术。

附录:

1、《spring揭穿》。

(转载本站文章请注明作者和出处 http://www.cnblogs.com/noahsark/ ,请勿用于任何商业用途)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: