SpringAOP源码详解

丶灬走出姿态 提交于 2019-12-03 06:35:01

SpringAOP是spring的动态代理模块。我们在spring的事务等多个方面都用到了springAOP方面的知识。

我们就以事务的动态代理原理解析来分析下springAOP的源码。

SpringAOP有几个核心概念:

    (1).切面Aspect: Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些切入点Pointcut 以及对切入点进行相应的操作的通知Advice。
    (2).连接点Joint point:表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它连接点jointpoint。
    (3).切入点Pointcut:表示一组连接点jointpoint,这些连接点或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的操作处理通知Advice将要发生的地方。
    (4).通知Advice:Advice 定义了在切入点pointcut 里面定义的程序点具体要做的操作和处理,它通过 before、after 和 around 来区别是在每个切入点之前、之后还是代替执行的代码。
    (5).目标对象Target:代理的目标对象,即切面要被应用到的目标对象。

    (6).织入Weave:指将切面应用到目标对象,并导致代理对象创建的过程

在AopConfigUtils初始化的时候InfrastructureAdvisorAutoProxyCreator被注册了,如下:

	static {
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
	}

InfrastructureAdvisorAutoProxyCreator继承结构图如下:

由图可知,这个类继承自BeanPostProcessor,那么就需要通过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;
	}

后面会找到所有合适的Advisor并创建代理类,如下:

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

在AbstractAdvisorAutoProxyCreator类中,这段代码找到合适的Advisor:

	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class beanClass, String beanName) {

		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}
在找到的advisor中,其中一个advisor就是TransactionAttributeSourceAdvisor,那么是怎么匹配TransactionAttributeSourceAdvisor是否合适的呢,在TransactionAttributeSourceAdvisor中有两个属性:
  • TransactionInterceptor
  • TransactionAttributeSourcePointcut

在这两个属性中,TransactionInterceptor就是我们上面所讲的advice,TransactionAttributeSourcePointcut就是我们上面所讲的pointcut。

	public Advice getAdvice() {
		return this.transactionInterceptor;
	}

	public Pointcut getPointcut() {
		return this.pointcut;
	}

最后在通过PointCut中的ClassFilter与MethodMatcher来匹配看对应的advisor是否合适:

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

为了方便读者代码追踪,其方法调用链如下(从beanPostProcessor开始):


最后会通过返回的advisor,获取相应的advice生成动态代理类。

另外springCache的缓存调用原理,与此一摸一样。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!