MyBatis源码学习(四)——创建Mapper动态代理

本文详细解析了MyBatis中Mapper动态代理的创建流程,包括创建Mapper代理工厂和生成Mapper动态代理两个阶段。重点介绍了Spring框架如何通过BeanPostProcessor预处理代理实例,以及如何利用MapperFactoryBean和MapperProxyFactory生成最终的Mapper动态代理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上小结:

  1. Spring标准代理创建流程,this.initializeBean()方法。
  2. BeanPostProcessor对Mapper代理实例进行预处理。
  3. 执行MapperFactoryBean.afterPropertiesSet(),从MapperFactoryBean.SqlSessionTemplate.SqlSessionFactory.Configuration.MapperRegistry.knownMappers获得之前创建好的工厂代理,如果没有则重新创建一个。
  4. 继续Spring标准代理创建流程,准备由MapperFactoryBean工厂代理创建Mapper动态代理。
  5. 调用MapperFactoryBean.newInstance(),创建MapperProxy,作为Mapper的动态代理。

 

正文:

在这一篇中,Mapper动态代理可以正式生成了,流程分为两部分:

  1. 第一部分是前文创建Mapper代理工厂准备工作的后续,其执行结果是创建了Mapper的代理工厂。
  2. 第二部分是用依赖注入的方式注入Mapper参数,并且正式生成Mapper的动态代理。

 

第一部分,创建Mapper代理工厂

在之前创建Mapper动态代理的准备工作中,我们看到,在doCreateBean()方法中,重点关注了两个方法:

this.populateBean(beanName, mbd, instanceWrapper);

和他的下一行:

exposedObject = this.initializeBean(beanName, exposedObject, mbd);

在之前的文章中分析了this.populateBean()方法,对Mapper实例进行属性注入,下面来分析一下this.initializeBean()方法,此方法用于生成Mapper的动态代理。

this.initializeBean()方法在AbstractAutowireCapableBeanFactory类中,其中的exposedObject参数就是前面BeanWrapper中预创建的代理实例,方法源码如下:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
       if (System.getSecurityManager() != null) {
              AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                     invokeAwareMethods(beanName, bean);
                     return null;
              }, getAccessControlContext());
       }
       else {
              invokeAwareMethods(beanName, bean);
       }

       Object wrappedBean = bean;
       if (mbd == null || !mbd.isSynthetic()) {
              wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
       }

       try {
              invokeInitMethods(beanName, wrappedBean, mbd);
       }
       catch (Throwable ex) {
              throw new BeanCreationException(
                            (mbd != null ? mbd.getResourceDescription() : null),
                            beanName, "Invocation of init method failed", ex);
       }
       if (mbd == null || !mbd.isSynthetic()) {
              wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
       }

       return wrappedBean;
}

方法最开始的:

invokeAwareMethods(beanName, bean);

此方法主要是处理实现类Aware接口的类,此接口是个标注接口,无具体方法。实现了此接口的类在初始化时会调用其setXXX()方法。Mybatis的Mapper没有实现Aware接口,这段忽略。

下面调用的是applyBeanPostProcessorsBeforeInitialization()方法,在这个方法中,会有一堆BeanPostProcessor对代理实例进行预处理:

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
              throws BeansException {

       Object result = existingBean;
       for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
              Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
              if (current == null) {
                     return result;
              }
              result = current;
       }
       return result;
}

预处理结束后,调用的是invokeInitMethods()方法,此方法主要用于执行代理类的afterPropertiesSet()方法,代码如下:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
              throws Throwable {

       boolean isInitializingBean = (bean instanceof InitializingBean);
       if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
              if (logger.isDebugEnabled()) {
                     logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
              }
              if (System.getSecurityManager() != null) {
                     try {
                            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                                   ((InitializingBean) bean).afterPropertiesSet();
                                   return null;
                            }, getAccessControlContext());
                     }
                     catch (PrivilegedActionException pae) {
                            throw pae.getException();
                     }
              }
              else {
                     ((InitializingBean) bean).afterPropertiesSet();
              }
       }

       if (mbd != null && bean.getClass() != NullBean.class) {
              String initMethodName = mbd.getInitMethodName();
              if (StringUtils.hasLength(initMethodName) &&
                            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                            !mbd.isExternallyManagedInitMethod(initMethodName)) {
                     invokeCustomInitMethod(beanName, bean, mbd);
              }
       }
}

可以看到,其中的

((InitializingBean) bean).afterPropertiesSet();

这一行调用的是bean的afterPropertiesSet()方法,bean的类型是由BeanDefinition决定的,在之前的代码中,BeanDefinition里bean的类型已经从本身的Mapper接口类变成了MapperFactoryBean类,所以此处执行的afterPropertiesSet()方法实际上是MapperFactoryBean类的afterPropertiesSet()方法。

afterPropertiesSet()方法实现在MapperFactoryBean类的父类的父类DaoSupport中,他们的继承关系是:

MapperFactoryBean<T> extends SqlSessionDaoSupport

SqlSessionDaoSupport extends DaoSupport

所以来看一下afterPropertiesSet()方法的代码:

public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
    this.checkDaoConfig();

    try {
        this.initDao();
    } catch (Exception var2) {
        throw new BeanInitializationException("Initialization of DAO failed", var2);
    }
}

方法首先调用的是this.checkDaoConfig(),实际上这个方法的实现在MapperFactoryBean类中:

protected void checkDaoConfig() {
    super.checkDaoConfig();
    Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
    Configuration configuration = this.getSqlSession().getConfiguration();
    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
        try {
            configuration.addMapper(this.mapperInterface);
        } catch (Exception var6) {
            this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);
            throw new IllegalArgumentException(var6);
        } finally {
            ErrorContext.instance().reset();
        }
    }

}

可见,方法先是调用了super.checkDaoConfig()方法,MapperFactoryBean的父类SqlSessionDaoSupport中这个方法只有一句断言:

protected void checkDaoConfig() {
    Assert.notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
}

继续向下看:

Configuration configuration = this.getSqlSession().getConfiguration();

其中getSqlSession()方法就是之前注入好的SqlSessionTemplate对象,而getConfiguration()方法是从SqlSessionTemplate对象中获取sqlSessionFactory对象然后再获取其Configuration对象,也就是这样:

configuration=MapperFactoryBean.SqlSessionTemplate.SqlSessionFactory.Configuration

继续往下:

configuration.hasMapper()方法,configuration对象中维护了一个MapperRegistry类,MapperRegistry类中有一个knownMappers 属性,类型是HashMap<Class<?>, MapperProxyFactory<?>>,用于保存已经加载好的动态代理,其中的key就是Mapper接口类。

在前面创建SqlSessionFactory的过程中,其实已经读取了配置的Mapper.xml文件,并依此生成了很多Mapper接口的代理工厂类,并添加到了knowMappers中,所以当我们要注入被@AutoWired注解的Mapper属性时,基本都可以从knowMappers中拿到其对应的代理工厂类。

如果Configuration中没有这个动态代理,则调用configuration.addMapper()方法添加,而且此代理是添加的时候重新生成的,configuration.addMapper()方法如下:

public <T> void addMapper(Class<T> type) {
  mapperRegistry.addMapper(type);
}

然后是mapperRegistry的addMapper()方法:

public <T> void addMapper(Class<T> type) {
  if (type.isInterface()) {
    if (hasMapper(type)) {
      throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
    }
    boolean loadCompleted = false;
    try {
      knownMappers.put(type, new MapperProxyFactory<T>(type));
      // It's important that the type is added before the parser is run
      // otherwise the binding may automatically be attempted by the
      // mapper parser. If the type is already known, it won't try.
      MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
      parser.parse();
      loadCompleted = true;
    } finally {
      if (!loadCompleted) {
        knownMappers.remove(type);
      }
    }
  }
}

以上流程和创建SqlSessionFactory时创建Mapper动态代理的流程基本一样。

至此,我们已经把Mapper的代理工厂准备好了,回到本篇最开始,doCreateBean()方法中

exposedObject = this.initializeBean(beanName, exposedObject, mbd);

这一行的目的就达到了,得到的exposedObject就是Mapper的代理工厂。

接下来有一段关于earlySingletonExposure的判断,执行了很多逻辑,主要目的是为了判断循环依赖时的依赖对象有没有被改变,改变了就抛异常,此处涉及Spring循环依赖的原理。

于是,doCreateBean()方法完成,调用它的createBean()方法完成,我们顺着调用栈回到AbstractBeanFactory的doGetBean()方法,刚刚执行的是

if (mbd.isSingleton()) {
	sharedInstance = getSingleton(beanName, () -> {
		try {
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {
			// Explicitly remove instance from singleton cache: It might have been put there
			// eagerly by the creation process, to allow for circular reference resolution.
			// Also remove any beans that received a temporary reference to the bean.
			destroySingleton(beanName);
			throw ex;
		}
	});
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

其中的getSingleton()方法执行完成,下面执行的是:

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

这行。

注意,虽然此处doGetBean()方法的代码在AbstractBeanFactory类中,但实际执行此方法的是一个DefaultListableBeanFactory实例,他们的继承关系是:

DefaultListableBeanFactory继承AbstractAutowireCapableBeanFactory继承AbstractBeanFactory

所以此处的getObjectForBeanInstance()方法是DefaultListableBeanFactory类的方法,实际的代码实现在其父类AbstractAutowireCapableBeanFactory中:

@Override
protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	String currentlyCreatedBean = this.currentlyCreatedBean.get();
	if (currentlyCreatedBean != null) {
		registerDependentBean(beanName, currentlyCreatedBean);
	}

	return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}

其中调用的:

return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);

才是执行AbstractBeanFactory中的方法:

protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	// Don't let calling code try to dereference the factory if the bean isn't a factory.
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
	}

	// Now we have the bean instance, which may be a normal bean or a FactoryBean.
	// If it's a FactoryBean, we use it to create a bean instance, unless the
	// caller actually wants a reference to the factory.
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
		return beanInstance;
	}

	Object object = null;
	if (mbd == null) {
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
		// Return bean instance from factory.
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// Caches object obtained from FactoryBean if it is a singleton.
		if (mbd == null && containsBeanDefinition(beanName)) {
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

注意其中这几行:

// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
       return beanInstance;
}

在这个判断中,Mapper的工厂代理会直接返回。

原因如下:第一个条件的结果是false,因为beanInstance确实是MapperFactoryBean(不要忘了前面的叹号),第二个条件的结果是true,BeanFactoryUtils.isFactoryDereference()的代码是这样的:

public static boolean isFactoryDereference(@Nullable String name) {
       return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}

也就是判断name是否是工厂类标识符(&)开头的。

在创建Mapper代理工厂的准备工作这篇文章中,可以知道Spring给所有的BeanDefinition创建代理时,给所有的工厂类名前面都加上了这个工厂类标识符,其中就包括Mapper的代理。

 

于是我们回到文章最开始的:

exposedObject = this.initializeBean(beanName, exposedObject, mbd);

我们得到的实际上就是Mapper的代理工厂。

 

第二部分,创建Mapper动态代理

当我们在Service中使用:

@Autowired
private OrderMapper orderMapper;

这种方式使用Mapper接口时,Spring会向Service的代理中注入OrderMapper的代理,也会通过getBean()等方法来创建或获取代理。

Spring检查并发现@Autowired代理的逻辑省略,我们从AbstractBeanFactory的getBean()方法开始看代码:

@Override
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

调用doGetBean()方法:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isDebugEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else {
		...
	}

	...
	return (T) bean;
}

此时sharedInstance已经有值了,所以bean通过此行代码获取:

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

注意,虽然此行代码在AbstractBeanFactory类中,但实际调用此代码的是DefaultListableBeanFactory类,他们的继承关系是:

DefaultListableBeanFactory继承AbstractAutowireCapableBeanFactory继承AbstractBeanFactory

getObjectForBeanInstance()方法实现在了AbstractAutowireCapableBeanFactory类中:

@Override
protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	String currentlyCreatedBean = this.currentlyCreatedBean.get();
	if (currentlyCreatedBean != null) {
		registerDependentBean(beanName, currentlyCreatedBean);
	}

	return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}

方法最后调用了父类的getObjectForBeanInstance()方法,也就是AbstractBeanFactory的方法:

protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	// Don't let calling code try to dereference the factory if the bean isn't a factory.
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
	}

	// Now we have the bean instance, which may be a normal bean or a FactoryBean.
	// If it's a FactoryBean, we use it to create a bean instance, unless the
	// caller actually wants a reference to the factory.
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
		return beanInstance;
	}

	Object object = null;
	if (mbd == null) {
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
		// Return bean instance from factory.
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// Caches object obtained from FactoryBean if it is a singleton.
		if (mbd == null && containsBeanDefinition(beanName)) {
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

生成Mapper代理工厂的时候就调用过这个方法,当时方法在

if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
       return beanInstance;
}

这一段就返回了,因为beanInstance是FactoryBean,所以第一个条件是true,name是工厂标识符开头的,所以第二个条件也是true。

这次不同了,虽然beanInstance还是FactoryBean,但是name是Mapper类原名,不包含工厂标识符,所以第二个条件是false,代码得以向后执行。

可见,Spring在这个方法中对工厂类和非工厂类进行了不同的处理方案:

  1. 非工厂类,直接返回之前生成的代理。
  2. 工厂类,生成代理工厂时,直接返回之前生成的代理。
  3. 工厂类,需要生成工厂中指定的具体代理时,向后执行,调用getObjectFromFactoryBean()方法。

 

在方法的最后,代码执行到这一行:

object = getObjectFromFactoryBean(factory, beanName, !synthetic);

getObjectFromFactoryBean()方法在AbstractBeanFactory的父类FactoryBeanRegistrySupport中:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
	if (factory.isSingleton() && containsSingleton(beanName)) {
		synchronized (getSingletonMutex()) {
			Object object = this.factoryBeanObjectCache.get(beanName);
			if (object == null) {
				object = doGetObjectFromFactoryBean(factory, beanName);
				// Only post-process and store if not put there already during getObject() call above
				// (e.g. because of circular reference processing triggered by custom getBean calls)
				Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
				if (alreadyThere != null) {
					object = alreadyThere;
				}
				else {
					if (shouldPostProcess) {
						try {
							object = postProcessObjectFromFactoryBean(object, beanName);
						}
						catch (Throwable ex) {
							throw new BeanCreationException(beanName,
									"Post-processing of FactoryBean's singleton object failed", ex);
						}
					}
					if (containsSingleton(beanName)) {
						this.factoryBeanObjectCache.put(beanName, object);
					}
				}
			}
			return object;
		}
	}
	else {
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		if (shouldPostProcess) {
			try {
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		return object;
	}
}

因为MapperFactoryBean都是单例的,第一次创建Mapper代理时缓存中也没有,所以代码一开始会执行到这一行:

object = doGetObjectFromFactoryBean(factory, beanName);

这就是从factory中获得一个具体动态代理的方法,看一下这个方法的代码:

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
		throws BeanCreationException {

	Object object;
	try {
		if (System.getSecurityManager() != null) {
			AccessControlContext acc = getAccessControlContext();
			try {
				object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			object = factory.getObject();
		}
	}
	catch (FactoryBeanNotInitializedException ex) {
		throw new BeanCurrentlyInCreationException(beanName, ex.toString());
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
	}

	// Do not accept a null value for a FactoryBean that's not fully
	// initialized yet: Many FactoryBeans just return null then.
	if (object == null) {
		if (isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		object = new NullBean();
	}
	return object;
}

代码逻辑比较简单,传入的factory参数就是Mapper的代理工厂MapperFactoryBean,主要关注这一行:

object = factory.getObject();

调用的就是MapperFactoryBean的getObject()方法:

public T getObject() throws Exception {
    return this.getSqlSession().getMapper(this.mapperInterface);
}

在此方法中,this.getSqlSession()方法得到的是SqlSessionTemplete,看一下其getMapper()方法:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  return mapperRegistry.getMapper(type, sqlSession);
}

然后是MapperRegistry类的getMapper()方法:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}

首先,从knowMappers里面按type获得之前生成的代理工厂实例MapperProxyFactory,然后调用他的newInstance()方法:

public T newInstance(SqlSession sqlSession) {
  final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}

建立一个MapperProxy实例,其中的mapperInterface参数就是代理工厂实例中记录的Mapper的接口类,这个实例将作为Mapper动态代理的调用处理程序,当我们用此代理调用一个方法时,将调用MapperProxy的invoke()方法。

此方法把这个MapperProxy实例作为参数传给了newInstance()方法:

protected T newInstance(MapperProxy<T> mapperProxy) {
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

在此方法中最终生成了Mapper的动态代理。这个代理会被Spring的依赖注入机制注入到其他的对象中,从而调用Mapper接口中的各个方法。

(本文结束)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值