本文介绍下Spring如何实例化Mapper的,中间省去了Mapper如何被扫描到,省去了Mapper转成Db
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
RootBeanDefinition mbd = MapperFactoryBean
//返回是class。org.mybatis.spring.mapper.MapperFactoryBean类型
Class<?> beanClass = mbd.getBeanClass();
疑问:那为什么Mapper在抓成DB的时候也是MapperFactoryBean,但是BeanClass却是UserInfoMapper类型
//mbd.isNonPublicAccessAllowed()返回的是true,执行beanClass.getDeclaredConstructors()方法,所以会拿到的所有构造方法
Constructor<?>[] candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors());
看下MapperFactoryBean的构造方法
public MapperFactoryBean() {
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
最终只取了有参的构造方法
Constructor<?> constructorToUse = 通过从candidates集合里面找到带有参数的构造方法
constructorToUse也就是带有参数的构造方法,通过newInstance就可以得到实例对象了。这个都是基于反射创建对象的,关于Constructor可以看我我的另一篇文章反射实例化对象
//这里得到也只是实例化MapperFactoryBean,不是UserInfoMapper
Object beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
最后会把上面得到的MapperFactoryBean实例对象转成BeanWrapperImpl,关于BeanWrapper的知识可以看我的另一篇文章BeanWrapper作用,这里的东西都有连贯性,BeanWrapper主要是为了方便修改实例对象MapperFactoryBean里面的属性,包含MapperFactoryBean继承的父类属性。
BeanWrapperImpl bw = new BeanWrapperImpl();
bw.setBeanInstance(beanInstance);
return bw;
上面已经得到了BeanWrapper,切确的是关于MapperFactoryBean类型相关的BeanWrapper,下面开始执行给MapperFactoryBean实例对象里面的属性赋值,这里就要通过BeanWrapper类来完成了
//BeanWrapper instanceWrapper = 上面得到的BeanWrapper对象
//RootBeanDefinition mbd = MapperFactoryBean
//String beanName = userInfoMapper也就我们的实际Mapper名称
//初始化instanceWrapper里面设置的MapperFactoryBean实例的属性
populateBean(beanName, mbd, instanceWrapper);
MapperFactoryBean有很多个属性,会每个属性都有set和get方法,依次执行对应属性的set方法,来给属性赋值,这里重点说一下SqlSessionFactory属性,为什么先看下SqlSessionFactory属性的set方法
private SqlSession sqlSession;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
//里面有个很重要的SqlSessionTemplate
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
但是你会发现MapperFactoryBean没有属性SqlSessionFactory,只是有对应的setSqlSessionFactory方法,那Spring是通过什么机制去触发setSqlSessionFactory方法的,原因很简单,setSqlSessionFactory方法上面带有了下面注解,只是编辑器反编译过来没有显示而已,为什么触发setSqlSessionFactory我当初找了半天也不知道
@Autowired
@Qualifier("sqlSessionFactory")
在设置属性的时候,最终会调用下面代码,关于通过MutablePropertyValues设置属性
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
//BeanWrapper bw = 上面代码传过来的对象
//List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
//deepCopy是通过属性遍历处理好的set方法名和属性值,这里不做过多的阐释
最终就是通过上面代码的方式调用了MapperBeanFactory里面属性的set方法,达到调用带有@Autowired注解的方法