MyBatis的mapper交给Spring管理源码解析

阅读此篇建议在阅读springioc之后的基础上阅读,后期会将ioc过程笔记整理在csdn上

MyBatis mapper接口如何被实例化为对象?

通过动态道理的方式:
通过MapperProxy 代理生成了代理对象mapper

public class MapperProxy implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private SqlSession sqlSession;

  private <T> MapperProxy(SqlSession sqlSession) {
    this.sqlSession = sqlSession;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (method.getDeclaringClass() == Object.class) {
      return method.invoke(this, args);
    }
    final Class<?> declaringInterface = findDeclaringInterface(proxy, method);
    final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);
    final Object result = mapperMethod.execute(args);
    if (result == null && method.getReturnType().isPrimitive() && !method.getReturnType().equals(Void.TYPE)) {
      throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

  private Class<?> findDeclaringInterface(Object proxy, Method method) {
    Class<?> declaringInterface = null;
    for (Class<?> iface : proxy.getClass().getInterfaces()) {
      try {
        Method m = iface.getMethod(method.getName(), method.getParameterTypes());
        if (declaringInterface != null) {
          throw new BindingException("Ambiguous method mapping.  Two mapper interfaces contain the identical method signature for " + method);
        } else if (m != null) {
          declaringInterface = iface;
        }
      } catch (Exception e) {
        // Intentionally ignore.
        // This is using exceptions for flow control,
        // but it's definitely faster.
      }
    }
    if (declaringInterface == null) {
      throw new BindingException("Could not find interface with the given method " + method);
    }
    return declaringInterface;
  }

  @SuppressWarnings("unchecked")
  public static <T> T newMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
    ClassLoader classLoader = mapperInterface.getClassLoader();
    Class<?>[] interfaces = new Class[]{mapperInterface};
    MapperProxy proxy = new MapperProxy(sqlSession);
    return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
  }

}

MapperRegistry 实现了对mapper的管理

public class MapperRegistry {

  private Configuration config;
  private Set<Class<?>> knownMappers = new HashSet<Class<?>>();

  public MapperRegistry(Configuration config) {
    this.config = config;
  }

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    if (!knownMappers.contains(type))
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    try {
      return MapperProxy.newMapperProxy(type, sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

  public boolean hasMapper(Class<?> type) {
    return knownMappers.contains(type);
  }

  public void addMapper(Class<?> type) {
    if (type.isInterface()) {
      if (knownMappers.contains(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        knownMappers.add(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);
        }
      }
    }
  }
}

第三方对象如何注入到Spring中?

	1.@Bean  @Component
	2.beanFactory.registerSingleton("tDao",tDao);
	3.FactoryBean
@Bean @Component
@Bean和@Component有什么不同呢?

@Bean 注解告诉spring这个方法要返回一个对象,这个对象要注册到spring的上下文
@Component 告诉spring要为这个类创建Bean

	这里Mybatis 是不能用这个方法的 因为 mapper接口通过动态代理实例化的,这里注释不能加载源码上;
beanFactory.registerSingleton(“tDao”,tDao);
 这个方法倒是可行的,但是写在代码中的话当运行到这一行代码,Spring IOC已经初始化完成;
FactoryBean

Mybatis用的就是这一种:

FactoryBean与BeanFactory区别?
*有没有想起 IOC过程中有一步是判断是否为FactoryBean*

BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似
BeanFactory和ApplicationContext就是spring框架的两个IOC容器,现在一般使用ApplicationnContext,其不但包含了BeanFactory的作用,同时还进行更多的扩展。
Mybatis就是通过FactoryBean注入的!
先看下BeanFactory接口

public interface FactoryBean<T> {

	/
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
	
	@Nullable
	T getObject() throws Exception;


	@Nullable
	Class<?> getObjectType();


	default boolean isSingleton() {
		return true;
	}

}

MapperFactoryBean 实现了FactoryBean 返回 代理对象 mapperInterface

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {

  private Class<T> mapperInterface;

  private boolean addToConfig = true;

 
  public void setMapperInterface(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }


  public void setAddToConfig(boolean addToConfig) {
    this.addToConfig = addToConfig;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected void checkDaoConfig() {
    super.checkDaoConfig();

    notNull(this.mapperInterface, "Property 'mapperInterface' is required");

    Configuration configuration = getSqlSession().getConfiguration();
    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
      try {
        configuration.addMapper(this.mapperInterface);
      } catch (Throwable t) {
        logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t);
        throw new IllegalArgumentException(t);
      } finally {
        ErrorContext.instance().reset();
      }
    }
  }

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

  /**
   * {@inheritDoc}
   */
  public Class<T> getObjectType() {
    return this.mapperInterface;
  }

  /**
   * {@inheritDoc}
   */
  public boolean isSingleton() {
    return true;
  }

}

在IOC实例化的方法
instanceWrapper = createBeanInstance(beanName, mbd, args);中instantiateUsingFactoryMethod方法

	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
省略
//判断是否通过工厂创建FactoryMethodName
		if (mbd.getFactoryMethodName() != null)  {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}
省略
		return instantiateBean(beanName, mbd);
	}

如有通过工厂方法创建的挂进入这个方法

public BeanWrapper instantiateUsingFactoryMethod(
			final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {

		BeanWrapperImpl bw = new BeanWrapperImpl();
		this.beanFactory.initBeanWrapper(bw);

		Object factoryBean;
		Class<?> factoryClass;
		boolean isStatic;

		String factoryBeanName = mbd.getFactoryBeanName();
		if (factoryBeanName != null) {
			if (factoryBeanName.equals(beanName)) {
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"factory-bean reference points back to the same bean definition");
			}
			// 根据factoryBeanName获取factoryBean对象。   这里的factoryBean获取到的就是上面的MapperFactoryBean
			factoryBean = this.beanFactory.getBean(factoryBeanName);
			if (factoryBean == null) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"factory-bean '" + factoryBeanName + "' returned null");
			}
			factoryClass = factoryBean.getClass();
			isStatic = false;
		}else{
		省略。。。
	}

至此就完成了mapper的实例化

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值