目录
2. ReflectiveMethodInvocation.proceed()
前面两篇系列文章已经详细介绍了Mapper接口的扫描过程和对应bean的创建过程。本文重点介绍mybatis执行SQL的过程。
DaoService的selectByName方法,拿到的personMapper对象已经是上文介绍的那个superMapperProxy对象。执行personMapper.selectByName(personName)方法,入参personName是"Hodey",其实就是执行的superMapperProxy的InvocationHandler.invoke(Object proxy, Method method, Object[] args)方法。
public String selectByName(String personName){
PersonInfo personInfo = personMapper.selectByName(personName);
return personInfo.toString();
}
我们进入JdkDynamicAopProxy的invoke方法(代理类为什么是JdkDynamicAopProxy,请参见上一篇文章)
1. JdkDynamicAopProxy#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
// 如果原始方法是equals(),hashcode(),则直接执行代理类的对应方法返回。
// 如果原始方法所在类实现了DecoratingProxy.class接口,做相应的处理后返回类对象
// 如果原始方法是Advised.class的实现类,那就直接返回对应的代理结果。
// 以上4条并不重要!读不懂不影响后续的理解。
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 主流程不会进入该分支
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 根据配置,为给定方法获取一个拦截表。
// persistenceExceptionTranslationInterceptor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// ReflectiveMethodInvocation是Spring AOP执行回调的载体。它会将代理对象,目标对象,目标方法,目标方法的入参,目标对象/方法所在类类型和拦截列表封装在一起。
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 重点在这里
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
TargetSource targetSource就是Mapper的代理对象MapperProxy@5773。try语句块中的前4个if..else分支不重要,读不懂没关系。先往下走,this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)根据配置,为给定方法method获取一个拦截表。这里获取到的chain中只有一个拦截器persistenceExceptionTranslationInterceptor,这个拦截器就是为代理targetSource而生的。接下来的invocation对象仅仅是将proxy, target, method, args, targetClass, chain这些参数用ReflectiveMethodInvocation类型封装起来。retVal = invocation.proceed()才是重点需要介绍的方法,它处理完成后会得到SQL查询的结果。最后通过method.getReturnType()拿到所需的查询对象类型,将得到的结果转换成该返回值类型后返回上层完成结果的输出。
2. ReflectiveMethodInvocation.proceed()
public Object proceed() throws Throwable {
// 这里其实就是找到当前需要哪个拦截器去执行
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 重点在这里
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 因为persistenceExceptionTranslationInterceptor没有实现InterceptorAndDynamicMethodMatcher,故会走else分支
// PersistenceExceptionTranslator是异常处理器用于处理DataAccessException 。如果后续流程中出现了异常,那么该拦截器可以进行相应的异常转换处理。
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
// PersistenceExceptionTranslationInterceptor.invoke处理完成后又回走进该方法,但是那个时候currentInterceptorIndex=0了。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
process方法比较绕,处理过程也很“奇葩”。从整体上看作者是使用了责任链模式+观察者模式的实现。下面我们一起来分析这个奇葩的实现:
this.currentInterceptorIndex默认值是-1。假如interceptorsAndDynamicMethodMatchers.size=1。那就会先去执行this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)即get(0)的那个dm.interceptor.invoke(this)。然后调用最后一行((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)。实际执行的是PersistenceExceptionTranslationInterceptor的invoke方法。
// org.springframework.dao.support.PersistenceExceptionTranslationInterceptor#invoke public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } // 这估计是我第一次在系列文章中对异常进行保留和注释 // 只要后续过程中有RuntimeException ex发生,那么PersistenceExceptionTranslationInterceptor就能进行相应的处理 catch (RuntimeException ex) { // Let it throw raw if the type of the exception is on the throws clause of the method. if (!this.alwaysTranslate && ReflectionUtils.declaresException(mi.getMethod(), ex.getClass())) { throw ex; } else { PersistenceExceptionTranslator translator = this.persistenceExceptionTranslator; if (translator == null) { translator = detectPersistenceExceptionTranslators(this.beanFactory); this.persistenceExceptionTranslator = translator; } throw DataAccessUtils.translateIfNecessary(ex, tran