mybatis源码-mapperFactoryBean

1,104 阅读4分钟

MapperFactoryBean 是个啥?

  1. MapperFactoryBean 是 实现了 FactoryBean 的工厂bean.
  2. 你日常调用的 dao 层接口就是 MapperFactoryBean实例化的.

为啥dao接口能够执行,我们都知道接口是不能实例化的,答案只有一个mybatis帮你 代理了 dao 接口

看下MapperFactoryBean的结构

除了上图 还实现了 FactoryBean

看下MapperFactoryBean的属性(包含父类的属性)

MapperFactoryBean
    Class<T> mapperInterface
    boolean addToConfig = true
    SqlSession sqlSession
    boolean externalSqlSession

FactoryBean

  1. FactoryBean 是spring 提供的一个顶层接口
  2. 实现了FactoryBean的bean比较特殊,getBean("xxx") 获取的是当前bean 的getObject() 的返回,getBean("&xxx") 才是当前工厂bean

看下spring 获取 factoryBean 的入口

org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(String, Class, Object[], boolean) 方法片段,spring不懂的可以看下我以前的文章

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		// Create bean instance.
		if (mbd.isSingleton()) {
			sharedInstance = getSingleton(beanName, () -> {
				try {
				    //创建bean
					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;
				}
			});
			//处理 FactoryBean 返回bean
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
		}	    
			    
			    
}
protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	...................................................

	// 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.
	//看到没 要实现了 FactoryBean 接口 并且 name 不包含 & 才能继续走下去
	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;
}

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;
					}
				..........................................
				return object;
			}
		}
		
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 {
			    //这里 调用了  factory的getObject方法
				object = factory.getObject();
			}
		}		

//好了 我们直接看下 mapperFactortBean 的 getObject
//看到这里 我们应该都知道了 dao 层 接口是被代理了
@Override
//我们的dao层接口实例化从这里开始
public T getObject() throws Exception {
    //这个地方两个方法,都有必要看下
    return getSqlSession().getMapper(this.mapperInterface);
}

//好吧,我们看到了直接返回的是当前 mapperFactoryBean的 sqlSession
//你以为就这么简单的结束了,并不是,你有没有想过这个 sqlSession 是哪里来的
 public SqlSession getSqlSession() {
    return this.sqlSession;
  }

//我观察了下有两个方法给sqlSession 赋值的,如下:
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (!this.externalSqlSession) {
      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }
}

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
    this.sqlSession = sqlSessionTemplate;
    this.externalSqlSession = true;
}

//看了上面的两个方法我总结出来 sqlSession 就是 sqlSessionTemplate
//sqlSessionTemplate 是由 sqlSessionFactory 创建的,知道为啥要先讲 sqlSessionFactory了吧
//那好吧,上面的方法是啥时候被调用的呢
//这个地方 在 @MapperScan 文章中说了 , mybatis 把我们的mapperFactorBean 的依赖注入模式改为了AUTOWIRE_BY_TYPE'
//这个依赖注入的模式 意味着 我们的bena 只需要 存在 set 方法 就会调用,所有上面的两个方法都会调用(我真的很佩服自己)
//然后 SqlSessionFactory 讲过了,SqlSessionTemplate 也是在 mybatisAutoConfig 中@Bean 创建的
//看下 sqlSession(应该说是sqlSesisonTemplate) 的getMapper 方法究竟干了什么
@Override
public <T> T getMapper(Class<T> type) {
    //获取 configuration 这个 configuration就是 sqlSessionFactory 里面的 configuration
    return getConfiguration().getMapper(type, this);
}

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //获取 mapperProxyFactory  这个东西 是在创建 sqlSessionFactory 时候放入的
    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);
    }
}
public T newInstance(SqlSession sqlSession) {
    // 这里,  MapperProxy 是 实现了InvocationHandler 的接口,看到这里,应该可以猜到,是使用的 jdk 的动态代理
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
}
//结束
@SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    //返回了代理对象
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}