spring--aop_1_源码分析之JdkDynamicAopProxy实现

aop 实现有两种方式
1. ProxyFactoryBean方式: 这种方式是通过配置实现
2. ProxyFactory方式:这种方式是通过编程实现

这里说 ProxyFactoryBean ,先上一张ProxyFactoryBean 的关系图,后面能用到。

示例代码:

/**
 * 代理接口,如果不是接口使用CGLIB代理
 */
public interface ProxyInterface {
    void m();
    void t();
}
/**
 * 目标对象,接口的实现类
 */
public class Target implements ProxyInterface {
    @Override
    public void m() {
        System.out.println("m");
    }

    @Override
    public void t() {
        System.out.println("t");
    }
}

/**
 * 通知器
 */
public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("BeforeAdvice.....");
    }
}
/**
 *  通知器
 */
public class AfterAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("AfterAdvice.....");
    }
}

定义一个接口ProxyInterface, 实现类为 Target,声明了两个advice,用来增强Target 方法。配置文件如下(advice 配置的顺序就是调用的顺序):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- 目标类 -->
    <bean id="target" class="com.masz.springtest.aop.proxy.Target"/>

    <!-- advice -->
    <bean id="beforeAdvice" class="com.masz.springtest.aop.proxy.BeforeAdvice"/>
    <bean id="afterAdvice" class="com.masz.springtest.aop.proxy.AfterAdvice"/>

    <!-- 增强代理对象,ProxyFactoryBean 是一个FactoryBean , getBean() 时会调用它的getObject() 方法 -->
    <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

        <!-- 代理接口,如果没有接口使用CGLIB生成代理类-->
        <property name="proxyInterfaces">
            <list>
                <value>com.masz.springtest.aop.proxy.ProxyInterface</value>
            </list>
        </property>
        <property name="singleton" value="true"/>  <!-- 是否是单例 -->
        <property name="target" ref="target"/>  <!-- 指定增强目标bean -->

        <!-- 拦截器名称 -->
        <property name="interceptorNames">
            <list>
                <value>beforeAdvice</value>
                <value>afterAdvice</value>
            </list>
        </property>
    </bean>
</beans>

测试:

public static void main(String[] args) {
	ConfigurableApplicationContext applicationContext = SpringApplication.run(AopTest.class, args);

	//直接获取目标类
	Target t = applicationContext.getBean(Target.class);
	t.m();

	//获取目标的代理。 关键的是:ProxyFactoryBean  是一个FactoryBean
	ProxyInterface  proxy = (ProxyInterface)applicationContext.getBean("targetProxy");
	proxy.m();
	System.exit(0);
}

运行结果:

m
BeforeAdvice.....
m
AfterAdvice.....

第一个方法没有被增强,第二个方法被增强了。

源码分析:

从代码中可以看到,通过applicationContext.getBean()获取ProxyFactoryBean, ProxyFactoryBean 是一个FactoryBean 所以getObject() 方法就是获取代理对象的入口方法。

ProxyFactoryBean.getObject() 源码:

@Override
@Nullable
public Object getObject() throws BeansException {
	//初始化advisor 链
	initializeAdvisorChain();
	
	//对singleton 和 prototype 类型区分,生成相应的proxy
	if (isSingleton()) {
		//是singleton,调用此方法生成代理对象
		return getSingletonInstance();
	}
	else {
		if (this.targetName == null) {
			logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
					"Enable prototype proxies by setting the 'targetName' property.");
		}
		//不是singleton,创建一个Prototype 的实例的代理对象
		return newPrototypeInstance();
	}
}

 initializeAdvisorChain()   初始化 advisor chain:

/**
 * 创建advisor 链。
 * advisor 信息从BeanFactory 来的,每当创建一个新的prototype实例被创建时,BeanFactory 就会被刷新。
 * 拦截器通过factory api 以编程的方式被添加,而且不受advisor改变的影响。
 
 过程: 
 这个初始化advisor 链,是应用第一次通过 ProxyFactoryBean 获取代理对象时触发的,
 advisor 链初始化完成之后,会读取配置中所有的通知器,这个读取比较简单就是调用容器的getBean()方法;
 然后把获取的advice 加入到 advisor 链中,这个过程是addAdvisorOnChainCreation() 方法实现
 
 */
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
	//这个是个标识位,标记通知器链是否已经初始化过了,如果已经初始化完了就直接返回。
	if (this.advisorChainInitialized) {
		return;
	}

	//配置的advice 不能是空的,如果没有配置advice就不用增强了。
	if (!ObjectUtils.isEmpty(this.interceptorNames)) {
	
		//所有的bean 都是BeanFactory 管理的,所以BeanFactory不能是空
		if (this.beanFactory == null) {
			throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
					"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
		}

		// Globals can't be last unless we specified a targetSource using the property...
		if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
				this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("Target required after globals");
		}

		//遍历所有的advice 名称配置,获取advice bean 并且添加到 advisor 链
		for (String name : this.interceptorNames) {
			if (logger.isTraceEnabled()) {
				logger.trace("Configuring advisor or advice '" + name + "'");
			}

			//interceptor name 是 * 结尾的
			if (name.endsWith(GLOBAL_SUFFIX)) {
				if (!(this.beanFactory instanceof ListableBeanFactory)) {
					throw new AopConfigException(
							"Can only use global advisors or interceptors with a ListableBeanFactory");
				}
				addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
						name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
			}

			else {
				// If we get here, we need to add a named interceptor.
				// We must check if it's a singleton or prototype.
				//程序运行到这里就要检查添加的 interceptor 是 singleton 还是 prototype 类型。
				
				Object advice;
				if (this.singleton || this.beanFactory.isSingleton(name)) {
					// Add the real Advisor/Advice to the chain.
					//单例的 advice,就从beanFactory 中get bean 了。
					advice = this.beanFactory.getBean(name);
				}
				else {
					// It's a prototype Advice or Advisor: replace with a prototype.
					// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
					//prototype advice,要创建一个新的advice
					advice = new PrototypePlaceholderAdvisor(name);
				}
				//添加advice 到 advisor chain
				addAdvisorOnChainCreation(advice, name);
			}
		}
	}
	this.advisorChainInitialized = true;
}

上面方法中的 addAdvisorOnChainCreation() 方法:
把配置 advice 封装成一个 DefaultPointcutAdvisor 对象,包含了PointCut(默认是Pointcut.TRUE) 和 advice。
然后把封装成的 advisor 放到 advisors 集合中,这个过程是在 类AdvisedSupport 中实现的,ProxyFactoryBean 是这个类的子类,看上图。

getSingletonInstance() 方法, 生成 singleton 代理对象。

/**
 * Return the singleton instance of this class's proxy object,
 * lazily creating it if it hasn't been created already.
 * @return the shared singleton proxy
 
 返回一个单例的代理对象,如果没有创建则会进行懒加载。
 
 过程:首先读取ProxyFactoryBean 的配置,为生成代理对象做好准备,如:代理接口,目录对象等。
 再通过AopProxy 生成代理对象。
 
 */
private synchronized Object getSingletonInstance() {
	//如果已经创建了,就直接返回
	if (this.singletonInstance == null) {
	
		this.targetSource = freshTargetSource();
		if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
			// Rely on AOP infrastructure to tell us what interfaces to proxy.
			//根据AOP 框架来判断需要代理的接口
			Class<?> targetClass = getTargetClass();
			
			if (targetClass == null) {
				throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
			}
			//设置代理对象的接口
			setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
		}
		// Initialize the shared singleton instance.
		super.setFrozen(this.freezeProxy);
		//getProxy()方法,通过createAopProxy() 方法返回的AopProxy 得到代理对象。
		this.singletonInstance = getProxy(createAopProxy());
	}
	return this.singletonInstance;
}
/**
 * getProxy() 方法出现了AopProxy 接口对象。
 */
protected Object getProxy(AopProxy aopProxy) {
	return aopProxy.getProxy(this.proxyClassLoader);
}

上面代码中 createAopProxy()  返回的是一个AopProxy对象,这个对象有两个实现类:JdkDynamicAopProxy,CglibAopProxy,看到名字就很清楚了分别对应生成代理类不同的实现方式。getProxy() 方法调用AopProxy 类的getProxy() 方法返回代理对象。
Spring 使用AopProxy 接口对象把AOP代理的实现和框架其它部分区分开,体现面向接口编程。

createAopProxy() 方法是在ProxyFactoryBean 父类 ProxyCreatorSupport 中实现的,ProxyCreatorSupport 中又调用了AopProxyFactory 默认实现 DefaultAopProxyFactory.createAopProxy() 方法生成AopProxy 代理对象。

/**
 * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
 * create an AOP proxy with {@code this} as an argument.
 
 子类调用这个方法生成 AOP proxy。
 
 在 AdvisedProxy 子类 ProxyFactoryBean 中通过 AopProxyFactory 来生成代理类,AdvisedProxy 封装了所有的生成代理对象信息,如:实现接口,目录类等。
 AopProxyFactory 使用的是 DefaultAopProxyFactory,这个对象在 ProxyFactoryBean 父类 ProxyCreatorSupport 中被创建。
 createAopProxy() 方法参数就是 AdvisedProxy 类型,这里传的是this,就是 ProxyFactoryBean,ProxyFactoryBean也是AdvisedProxy子类(可以查看上面的类关系图)。
 
 */
protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();
	}
	return getAopProxyFactory().createAopProxy(this);
}

//这里是调用 AopProxyFactory 默认实现 DefaultAopProxyFactory.createAopProxy() 方法生成AopProxy 代理对象。
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
	
		//目录对象的class
		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.");
		}
		//targetClass 是接口类,使用 JDK来生成 Proxy
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		//如果不是接口类,使用CGLIB 生成代理对象
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

JdkDynamicAopProxy 源码分析:

JdkDynamicAopProxy 本身实现了 InvocationHandler 接口和 AopProxy 接口所以 JdkDynamicAopProxy实现的InvocationHandler.invoker() 方法就是Proxy 对象回调的方法。
实现的AopProxy.getProxy() 方法就是通过JDK动态代理生成的代理对象,传递的InvocationHandler 对象就是 JdkDynamicAopProxy 自身。
这就是动态代理了,切面的实惠就是在 invoke() 方法中体现的。后面再分析如何实现AOP。

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
	}
	//获取目标类上的接口并且判断是否需要添加SpringProxy  Advised DecoratingProxy(spring4.3 新增) 接口
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
	
	//判断的目标对象实现的接口是否定义了equals或hashCode方法,
	//在invoke() 方法调用的时候会对 equals 和 equals 做特殊的处理,参考后面
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	
	//返回动态代理对象
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

总结:
通过AopProxy 对象封装target 目标对象之后,ProxyFactoryBean方法得到的对象已经是一个AopProxy代理对象了,在ProxyFactoryBean 中配置的target目标对象不会让应用直接调用其方法的实现,对target目标对象的方法调用会被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。对于 JDK的AopProxy代理对象,使用的是InvocationHander的invoker 回调入口。对于CGLIB的AopProxy代理对象,使用的是设置好的callbak 回调,在这里callback回调中,对于AOP的实现是通过DynamicAdvisedInterceptor 来完成的,DynamicAdvisedInterceptor 的回调入口是 intercept 方法(后面再分析CGLIB)。
这里只是AopProxy 代理对象的生成,通过这个过程把代理对象和拦截器待调用的部分都准备好。下面就分析AOP运行过程中对这些拦截器和代理对象的调用过程。

AOP 拦截器调用实现:

如果是JDK实现的代理对象就会通过InvocationHandler 来完成拦截器回调,如果是CGLIB 就通过DynamicAdvisedInterceptor 来完成回调。
JdkDynamicAopProxy 的 invoke 拦截:
在 JdkDynamicAopProxy.getProxy() 方法中,调用的的JDK动态代理生成代理类,JdkDynamicAopProxy 自身实现了InvocationHandler 接口,那么代理对象调用目标对象方法时会被invoke() 方法拦截
 

JdkDynamicAopProxy.invoke() 源码:

@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	MethodInvocation invocation;
	Object oldProxy = null;
	boolean setProxyContext = false;

	//从advised中获取目标对象
	TargetSource targetSource = this.advised.targetSource;
	Object target = null;

	try {
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			// The target does not implement the equals(Object) method itself.
			//目标对象没有重写Object 的equals() 方法
			return equals(args[0]);
		}
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			// The target does not implement the hashCode() method itself.
			//目标对象没有重写 Object的 hashCode() 方法
			return hashCode();
		}
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			// There is only getDecoratedClass() declared -> dispatch to proxy config.
			// 如果方法是在DecoratingProxy声明的,
			// DecoratingProxy 只有getDecoratedClass() 一个方法,所有在这里直接调用
			// 返回代理类的终极目标类。
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			// Service invocations on ProxyConfig with the proxy config...
			//Spring AOP不会增强直接实现Advised接口的目标对象。
			//这里直接通过反射调用。
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}

		//返回值
		Object retVal;

		//是否暴露代理对象,如果暴露意味着在线程内共享代理对象,在线程内可通过AopContext 获取代理对象。就是通过ThreadLocal 实现的。
		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		// Get as late as possible to minimize the time we "own" the target,
		// in case it comes from a pool.
		// 目标对象
		target = targetSource.getTarget();
		// 目标对象类
		Class<?> targetClass = (target != null ? target.getClass() : null);

		// Get the interception chain for this method.
		//获取目标方法的拦截器链
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		// Check whether we have any advice. If we don't, we can fallback on direct
		// reflective invocation of the target, and avoid creating a MethodInvocation.
		// 检查是否的拦截器,如果没有那么就直接通过反射调用目标方法,MethodInvocation就不用创建了
		if (chain.isEmpty()) {
			// We can skip creating a MethodInvocation: just invoke the target directly
			// Note that the final invoker must be an InvokerInterceptor so we know it does
			// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
			//如果没有拦截器,就不用创建 MethodInvocation,直接在目标对象上反射调用方法
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			// We need to create a method invocation...
			//创建一个 ReflectiveMethodInvocation,这个类是实现AOP的功能的封装
			invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// Proceed to the joinpoint through the interceptor chain.
			retVal = invocation.proceed();
		}

		// Massage return value if necessary.
		Class<?> returnType = method.getReturnType();
		// retVal不空 并且和目标方法的返回类型一致,就返回。
		if (retVal != null && retVal == target &&
				returnType != Object.class && returnType.isInstance(proxy) &&
				!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			// Special case: it returned "this" and the return type of the method
			// is type-compatible. Note that we can't help if the target sets
			// a reference to itself in another returned object.
			retVal = proxy;
		}
		else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
			throw new AopInvocationException(
					"Null return value from advice does not match primitive return type for: " + method);
		}
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			// Must have come from TargetSource.
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

注:
invoke 方法中获取调用拦截器链方法
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
这个方法把 PintcutAdvice 封装成 MethodInterceptor。MethodInterceptor 有两个实现类具体的为 MethodBeforeAdviceInterceptor 和 AfterReturningAdviceInterceptor 
MethodInterceptor.invoke() 方法,将的 ReflectiveMethodInvocation.proceed() 中被调用,MethodInterceptor.invoke()方法的参数就是 MethodInvocation 类型,而 ReflectiveMethodInvocation 是 MethodInvocation 的子类,在invoke() 方法中又回调了 MethodInvocation.proceed()方法,这样就又回调回去了,当 "this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1" 时也就是拦截器调用完了,就通过反射调用目标方法。
ReflectiveMethodInvocation 和 MethodInterceptor 就是实现Spring AOP 的核心所在。具体查看MethodBeforeAdviceInterceptor 和 AfterReturningAdviceInterceptor 这个两个实现源码就

JdkDynamicAopProxy AOP功能,就是通过 ReflectiveMethodInvocation 类实现的

ReflectiveMethodInvocation.proceed() 源码分析:

//这个方法是递归方法,当所有拦截器都执行完毕了,就通过反射调用目标方法返回。
@Override
@Nullable
public Object proceed() throws Throwable {

	//	We start with an index of -1 and increment early.
	//使用 currentInterceptorIndex 记录拦截器调用的下标,当所有拦截器都调用完毕后,通过反射调用目标方法。
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		//反射调用目标方法
		return invokeJoinpoint();
	}

	//从拦截器链中获取一个拦截器,下标是  ++this.currentInterceptorIndex
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		// Evaluate dynamic method matcher here: static part will already have
		// been evaluated and found to match.
		
		//动态匹配
		InterceptorAndDynamicMethodMatcher dm =
				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
				
		//如果方法和定义的切点匹配成功就执行
		if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		else {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			return proceed();
		}
	}
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		//执行到这里就是一个 MethodInterceptor , 则直接调用
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

在示例代码中配置的是通知器,不是切面,如果配置的是切面就要走动态匹配了(动态匹配就是走jdk的正则匹配 MethodMatcher ,不扩展了)。

总结:每个 MethodInterceptor 对应的都有实现AfterReturningAdviceInterceptor, MethodBeforeAdviceInterceptor, ThrowsAdviceInterceptor。如 MethodBeforeAdviceInterceptor

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

则是调用完invoke() 方法后,就又调用了MethodInvocation.proceed() 方法,又回到了上一步方法中,这样一直循环调用,直到所有的interceptor 调用完毕。

总结:ProxyFactoryBean 通过jdk动态代理机制生成代理对象,当调用代理对象方法时,会被invoke() 方法拦截。在invoke() 方法中又获取了此方法的拦截器,通过对拦截器的调用实现了spring aop功能。CGLIB的实现只是生成代理对象的方式不同,这就让拦截器的入口有了变化。拦截器的生成和调用机制是一样的。看第二篇。

注:这里通过 initializeAdvisorChain(); 把advice 封装成了advisor,又如何把advisor 封装成具体的interceptor 呢? 看后续...

猜你喜欢

转载自blog.csdn.net/convict_eva/article/details/81084833
今日推荐