目录
1.2 sqlSessionFactorybean与SqlSessionTemplate的创建
2.2 postProcessObjectFromFactoryBean
上一篇文章重点介绍了@MapperScan("backage")将指定backage中XXXMapper类解析成beanDefinition,随后修改了beanDefinition中beanClass属性,将属性值从XXXMapper替换为了MapperFactoryBean类型。本节将深入分析MapperFactoryBean的实例化和Mapper的依赖注入过程。如果你对bean的实例化过程和依赖注入过程不太熟悉的话,我强烈建议你阅读之前的两篇文章:
《【六】Spring IoC 最全源码详解之bean实例化过程》和《【七】Spring IoC 最全源码详解之bean的依赖注入》。如果你已经比较熟悉Spring的IoC流程了,那么我们就开始吧。本文在有基础的情况下,建议阅读时间4小时。
1. MapperFactoryBean的实例化
我们知道在创建daoService这个bean的过程中,在populateBean进行自动装配这一步骤时,会对加上了@Autowired注解的属性PersonMapper personMapper进行自动装配时会调用bean工厂的getBean(beanName)尝试获取或者创建一个目标对象名是beanName的bean注入到personMapper属性上完成自动装配。因为PersonMapper对应的bd中,beanClass已经被替换为MapperFactoryBean,所以beanName为personMapper所对应的bean其实是MapperFactoryBean类型的对象。MapperFactoryBean对象通过带参的构造函数进行实例化,构造参数是Mapper类型PersonMapper.class。当MapperFactoryBean对象实例化之后,也需要对其执行自动装配。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
..省略..
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
//按byType方式进行自动装配
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
..省略..
}
因为beanDefinition已经被设置成按AUTOWIRE_BY_TYPE类型装配,所以在populateBean方法中会执行autowireByType方法
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// converter的类型是org.mybatis.spring.mapper.MapperFactoryBean
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 最终得到的属性名是 "sqlSessionFactory" 和 "sqlSessionTemplate"。
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
// 获得属性的描述对象
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// 根据属性的描述,如果这个对象不是Object.class类才会进入if分支。因为没办法对Object.clss进行byType的自动装配。
if (Object.class != pd.getPropertyType()) {
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
registerDependentBean(autowiredBeanName, beanName);
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
重要的方法是在String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw)。返回不满足的非简单bean属性数组。什么是非简单bean属性呢?请见下图:
unsatisfiedNonSimpleProperties方法最终得到的属性名是 "sqlSessionFactory" 和 "sqlSessionTemplate"。也就是说要MapperFactoryBean依赖于sqlSessionFactory和sqlSessionTemplate这两个对象。这两个对象在哪里呢? 在org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration中通过@Bean标注。
1.1 Springboot自动配置与@Bean方法的扫描
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
Configuration configuration = this.properties.getConfiguration();
if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
configuration = new Configuration();
}
if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);
}
}
factory.setConfiguration(configuration);
if (this.properties.getConfigurationProperties() != null) {
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
}
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
return factory.getObject();
}
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
Springboot项目的启动类上往往有@SpringBootApplication注解,点进去看会发现它含有一个@EnableAutoConfiguration注解。再点进去看发现有一个@Import(AutoConfigurationImportSelector.class)注解。
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration
进入AutoConfigurationImportSelector.class找到getCandidateConfigurations方法。该方法的作用是委托SpringFactoriesLoader.lodaFactoryNames方法从各个依赖包的META-INF/spring.factories路径下找到自动配置类的类名。找到类名后就可以通过反射实例化该对象。理解了该机制,就理解了Springboot自动配置的精髓。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
回到本项目中。在MapperFactoryBean实例化过程中,会首先根据mybatis-spring-boot-autoconfigure中META-INF/spring.factories中的内容获取到MybatisAutoConfiguration这个配置类类名。在后续的bean创建过程中,MybatisAutoConfiguration类的对象会被创