spring源码解读 AOP原理

本文主要分析通过<aop:config>这种标签来使用spring AOP的过程。Spring版本是4.1.7。在我看来Spring AOP主要分四个步骤,加载解析AOP标签,生成代理对象,拦截器的调用。下面就是通过这四个方面来分析Spring AOP的原理。

一.容器初始化,解析AOP标签。

1.先看一下我跟源码时关于AOP的配置

      <aop:config>
      	<aop:aspect ref="print">
      		<aop:pointcut expression="execution(* aop.*.do*(..))" id="pointcut" />
      		<aop:after method="printLog" pointcut-ref="pointcut"/>
      	</aop:aspect>
      </aop:config> 

2.spring 在容器初始化时会通过一系列的BeanDefinitionParser将我们定义的内容解析成Spring内部的使用的数据结构BeanDefinition。spring 容器初始化的过程,不在多说,主要说明一下AOP标签解析的过程。AOP标签解析的入口

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						//解析除了Bean标签之外的其它标签
						//AOP标签解析的入口
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

在spring中bean标签是default,其它的任何标签都是custom。我们接着跟代码

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

获取NamespaceHandler的过程主要就是通过命名空间
http://www.springframework.org/schema/aop,找到定义标签的Handler文件,在spring-aop的jar包里META—INF里的spring.handlers,内容如下:

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

Spring对不同的命名空间都有相对应的NamespaceHandler。从上面的内容可以看出处理AOP命名空间的是AopNamespaceHandler,我们看一下AopNamespaceHandler里的内容。

public class AopNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	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());
	}

}

从中可以看出NameSpaceHandler主要是来注册用来解析标签的BeanDefitionParser,解析<aop:config>标签的是ConfigBeanDefitionParser,看一下主要的解析过程

public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
		//解析<aop:config>标签
		parserContext.pushContainingComponent(compositeDef);

		configureAutoProxyCreator(parserContext, element);

		List<Element> childElts = DomUtils.getChildElements(element);
		for (Element elt: childElts) {
			String localName = parserContext.getDelegate().getLocalName(elt);
			//解析<aop:pointcut>标签
			if (POINTCUT.equals(localName)) {
				parsePointcut(elt, parserContext);
			}
			//解析<aop:padvisor>标签
			else if (ADVISOR.equals(localName)) {
				parseAdvisor(elt, parserContext);
			//解析<aop:aspect>标签
			else if (ASPECT.equals(localName)) {
				parseAspect(elt, parserContext);
			}
		}

		parserContext.popAndRegisterContainingComponent();
		return null;
	}

在解析<aop:config>的子标签时都是生成BeanDefinition,在BeanFactory中有个重要属性beanDefinitionMap,里面保存着解析的结果,大家调试的时候可以看下里面除了你定义的bean之外,还有Aop标签的解析结果。在解析<aop:config>是有个重要的步骤,如下

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
		return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
	}

向BeanFactory中AspectJAwareAdvisorAutoProxyCreator,这个其实就是个BeanPostProcessor,对spring了解的可以知道,这是spring对外暴露的扩展点,里面定义了俩个方法,postProcessBeforeInstantiation在bean初始化之前,postProcessAfterInitialization在Bean初始化之后
用。
AspectJAwareAdvisorAutoProxyCreator
这个东西就是我们要找的东西,因为有了它我们才会生成代理对象。

二.生成代理对象。

1.在通过getBean()触发依赖注入之后,spring先生成对象的实例,然后进行初始化,在完成初始化之后会调用BeanPostProcessor的
postProcessAfterInitialization()方法,这里就是生成代理对象的入口。上面我们说了spring在解析Aop标签时会向容器注入AspectJAwareAdvisorAutoProxyCreator,其postProcessAfterInitialization的方法在父类AbstractAutoProxyCreator里,我们看一下其方法的实现:

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

在看一下

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		//1.判断是否有advisor和当前bean的class匹配
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//2.来生成代理对象
			Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

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

其中1的主要逻辑在AopUtils中,我们看一下主要的过程

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		MethodMatcher methodMatcher = pc.getMethodMatcher();
		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}

		Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		classes.add(targetClass);
		for (Class<?> clazz : classes) {
			Method[] methods = clazz.getMethods();
			for (Method method : methods) {
				if ((introductionAwareMethodMatcher != null &&
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

主要过程就是获取所有配置的advisor,然后循序校验,先判断类名是不是匹配,如果匹配则判断是不是有方法匹配。
生成代理对象有俩中策略,一种是JDK的动态代理,还有一种是Cglib,由于我并不是很了解Cglib我们看一下JDK动态的代理。

public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

很熟悉的东西。

三.拦截器的调用。

先看一下
CglibAopProxy里的i
ntercept()方法

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Class<?> targetClass = null;
			Object target = null;
			try {
				if (this.advised.exposeProxy) {
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				//获取目标类
				target = getTarget();
				if (target != null) {
					targetClass = target.getClass();
				}
				//1.获取拦截器链
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;
				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
					//没有匹配的拦截器则直接执行目标方法
					retVal = methodProxy.invoke(target, args);
				}
				else {
					//2.执行匹配的拦截器链
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null) {
					releaseTarget(target);
				}
				if (setProxyContext) {
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

先看一下如何获取匹配的拦截器,

@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, Class<?> targetClass) {

		List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
		//根据配置文件获取advisor集合,然后循环遍历
		for (Advisor advisor : config.getAdvisors()) {
			if (advisor instanceof PointcutAdvisor) {
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				//class是否匹配
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					//方法名是否匹配
					if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
						if (mm.isRuntime()) {
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

根据要执行的实例的类名,方法名循环遍历配置的advisor来判断。
我们最后在看一下是怎么执行的

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

在这里就分析完了。

    原文作者:AOP
    原文地址: https://blog.csdn.net/u012469740/article/details/61328542
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞