Spring-源码-实例化@Mapper

本文介绍下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主要是为了方便修改实例对象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注解的方法

经验分享 程序员 微信小程序 职场和发展