Spring AOP的实现原理之代理创建

在上一篇文章中,已经分析了当前匹配目标类的增强器的获取。

在wrapIfNecessary()方法中若获取的增强器不为空,则为之创建代理

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, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

代理的创建委托给了ProxyFactory

protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

		ProxyFactory proxyFactory = new ProxyFactory();
		// 获取当前类中的相关属性,比如proxyTargetClass,exposeProxy.
		proxyFactory.copyFrom(this);

		if (!shouldProxyTargetClass(beanClass, beanName)) {
			//获取目标类所实现的接口
			Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
			for (Class<?> targetInterface : targetInterfaces) {
				proxyFactory.addInterface(targetInterface);
			}
		}
		//封装Advisor到proxyFactory,其中涉及拦截器、增强方法的封装
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		for (Advisor advisor : advisors) {
			proxyFactory.addAdvisor(advisor);
		}

		proxyFactory.setTargetSource(targetSource);
		...
		return proxyFactory.getProxy(this.proxyClassLoader);
	}

由于Spring还涉及了拦截器(实现了MethodIntecptor接口)、增强方法等方式来对逻辑进行增强,因此此处统一封装成Advisor类型进行统一处理

接下来就是代理的创建了,如刚刚所说,代理的创建委托给了ProxyFactory

	public Object getProxy(ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}

跟踪下去,可以看见Spring可以通过两种方式创建代理,一种是JDK动态代理,另外一种是CGLIB代理

	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface()) {
				return new JdkDynamicAopProxy(config);
			}
			//CGLIB代理
			return CglibProxyFactory.createCglibProxy(config);
		}
		else {
			//JDK动态代理
			return new JdkDynamicAopProxy(config);
		}
	}

Spring是如何选择的呢?

从If判断条件可以看到:optimize,proxyTargetClass,hasNoUserSuppliedProxyInterfaces能影响spring的选择方式

optimize:用来控制通过CGLIB创建的代理是否使用激进的优化策略,可能我们对这个属性不怎么了解。
proxyTargetClass这个就是我们在分析<aop:aspectj-autoproxy>,若指定了proxy-target-class属性为true,则使用CGLIB代理

<aop:aspectj-autoproxy proxy-target-class="true"/>

hasNoUserSuppliedProxyInterfaces是否存在代理接口

一般来说,现在基本就是面向接口编程,所以一般service层均实现了接口,spring默认情况会使用JDK动态代理。

先看看CglibProxyFactory.getProxy()方法

public Object getProxy(ClassLoader classLoader) {
		...
		try {
			Class<?> rootClass = this.advised.getTargetClass();
			...
			// Configure CGLIB Enhancer...
			Enhancer enhancer = createEnhancer();
			...
			//设置代理目标类
			enhancer.setSuperclass(proxySuperClass);
			...
			Callback[] callbacks = getCallbacks(rootClass);
			...
			//设置callback
			enhancer.setCallbacks(callbacks);
			// 创建代理
			Object proxy;
			if (this.constructorArgs != null) {
				proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
			}
			else {
				proxy = enhancer.create();
			}
			return proxy;
		}
		...
	}

上面的代码即是使用CGLIB代理的一般步骤:

1、创建Enhancer

2、设置代理目标类

3、设置callback,其中返回的callback均是DynamicAdvisedInterceptor类型,明显该类实现了MethodInterceptor,当调用目标类的方法时,就会调用intercept()方法

4、创建代理

因此此时getBean(beanName)返回的就是一个代理了。

当我们获取bean并调用其方法时

Object object = applicationContext.getBean("xxx");
object.someMethod();

此时就会调用到DynamicAdvisedInterceptor,intercept()方法

	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			...
			try {
				//expose-proxy属性使得对于目标对象内部的自我调用也能增强
				if (this.advised.exposeProxy) {
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				...
				//获取拦截器链
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;
				// 如若拦截器链为空则直接调用目标类的原方法
				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
					retVal = methodProxy.invoke(target, args);
				}
				else {
					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) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

当然最重要的莫过于获取拦截器链,spring获取拦截器链的大致做法是把该增强器里的各种通知增强到方法中,比如若存在@After通知,则把相应的AspectJAfterAdvice加入进拦截器链等。

然后就调用CglibMethodInvocation.proceed();

public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		//获取下一个拦截器
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			//动态调用?
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				return proceed();
			}
		}
		//一般我们通过注解配置的就属于普通拦截器
		else {
			//普通拦截器,直接调用
			//MethodBeforeAdviceInterceptor对应@Before
			//AspectJAroundAdvice对应@Around
			//AspectJAfterAdvice对应@After
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

currentInterceptorIndex初始值为-1,当拦截器链都执行完了,if判断条件成立即会调用目标方法。

invoke()方法将this作为参数传递保证了递归调用。

比如在MethodBeforeAdviceInterceptor

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

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

}
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice {
 ...
 public void before(Method method, Object[] args, Object target) throws Throwable {
 invokeAdviceMethod(getJoinPointMatch(), null, null);
 }
}

执行完了@Before方法之后,又会调用proceed()方法,形成递归调用,从代码中也可以看到@Before通知是在目标方法之前调用

@After通知	
public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {

	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

同理,也可以看到@After通知是在目标方法执行完之后执行。

这些通知在执行各自的方法都会调用AbstractAspectJAdvice中的invokeAdviceMethod方法,当然spring同样是通过反射能到方法调用的

	protected Object invokeAdviceMethod(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable t)
			throws Throwable {

		return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
	}
	protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
		...
		try {
			//利用反射调用方法
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
		}
		..
	}

@Around通知就稍微有点复杂

@Around通知
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor {
	...
	public Object invoke(MethodInvocation mi) throws Throwable {
		if (!(mi instanceof ProxyMethodInvocation)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}
		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
		JoinPointMatch jpm = getJoinPointMatch(pmi);
		return invokeAdviceMethod(pjp, jpm, null, null);
	}
}

如上分析,当调用到方法标有@Around时

    @Around("test()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("around-begin");
		Object object = pjp.proceed();
		System.out.println("around-end");
		return object;
	}

pjp.proceed()会克隆MethodInvocation在调用proceed()方法继续执行拦截器链

	public Object proceed() throws Throwable {
		return this.methodInvocation.invocableClone().proceed();
	}

因为是递归调用,所以当执行完目标方法之后就程序就会回到around方法中,执行后续操作。

对于JDK动态代理,只是在初始化的时候不一样,其他基本同CGLIB代理类似,这里不做分析。

以上基本就是AOP的基本原理了。

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