2、MyBatis初始化过程

重点是SqlSessionFactory、SqlSession、Mapper、xml解析

mybatis:
  type-aliases-package: com.cmb.test.entity
  mapper-locations: classpath:mybatis/*Mapper.xml

从我们的老朋友xxAutoConfiguration开始,这次是MybatisAutoConfiguration

@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
  SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    // 设置数据源,HikariDataSource
  factory.setDataSource(dataSource);
    // SpringBootVFS,作用是类扫描
  factory.setVfs(SpringBootVFS.class);
    // yaml文件是否配置了configLocation
  if (StringUtils.hasText(this.properties.getConfigLocation())) {
    factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
  }
    // 如果在yaml配置了mybatis.configuration.xxxx属性,这里configuration就不会为,否则为空
    // 为空会new一个默认的Configuraiton,自带一些默认的属性
  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());
  }
    // typeHandler,类型转换器,比如Date和时间戳的转换。定义之后可以在mapper.xml中指定typeHandler
  if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
    factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
  }
    // 配置的mapper.xml
  if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
    factory.setMapperLocations(this.properties.resolveMapperLocations());
  }
 
  return factory.getObject();
}

factory.getObject()

@Override
public SqlSessionFactory getObject() throws Exception {
  if (this.sqlSessionFactory == null) {
    afterPropertiesSet();
  }
 
  return this.sqlSessionFactory;
}

 
@Override
public void afterPropertiesSet() throws Exception {
  notNull(dataSource, "Property 'dataSource' is required");
  notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
  state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
            "Property 'configuration' and 'configLocation' can not specified with together");
 
  this.sqlSessionFactory = buildSqlSessionFactory();
}

buildSqlSessionFactory();

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
 
  Configuration configuration;
 
  XMLConfigBuilder xmlConfigBuilder = null;
  if (this.configuration != null) {
    configuration = this.configuration;
    // 是否配置了variables,暂时不知道有什么用
    if (configuration.getVariables() == null) {
      configuration.setVariables(this.configurationProperties);
    } else if (this.configurationProperties != null) {
      configuration.getVariables().putAll(this.configurationProperties);
    }
    // 如果在yaml中配置了configLocation,就会去解析xml文件
  } else if (this.configLocation != null) {
    xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
    configuration = xmlConfigBuilder.getConfiguration();
  } else {
    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
    }
    configuration = new Configuration();
    if (this.configurationProperties != null) {
      configuration.setVariables(this.configurationProperties);
    }
  }
 
    // 为空
  if (this.objectFactory != null) {
    configuration.setObjectFactory(this.objectFactory);
  }
    // 为空
  if (this.objectWrapperFactory != null) {
    configuration.setObjectWrapperFactory(this.objectWrapperFactory);
  }
 
    // SpringBootVFS,在扫描typeAliasPakeage时会用到
  if (this.vfs != null) {
    configuration.setVfsImpl(this.vfs);
  }
 
    // 注册别名
  if (hasLength(this.typeAliasesPackage)) {
    String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
        ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
    for (String packageToScan : typeAliasPackageArray) {
      configuration.getTypeAliasRegistry().registerAliases(packageToScan,
              typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
      }
    }
  }
 
  if (!isEmpty(this.typeAliases)) {
    for (Class typeAlias : this.typeAliases) {
      configuration.getTypeAliasRegistry().registerAlias(typeAlias);
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Registered type alias: '" + typeAlias + "'");
      }
    }
  }
 
    // 加载自定义的拦截器
  if (!isEmpty(this.plugins)) {
    for (Interceptor plugin : this.plugins) {
      configuration.addInterceptor(plugin);
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Registered plugin: '" + plugin + "'");
      }
    }
  }
 
    // 定义自己的类型转换器,比如mybatis.type-handlers-package=com.cmb.test.handler
  if (hasLength(this.typeHandlersPackage)) {
    String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
        ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
    for (String packageToScan : typeHandlersPackageArray) {
      configuration.getTypeHandlerRegistry().register(packageToScan);
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");
      }
    }
  }
 
  if (!isEmpty(this.typeHandlers)) {
    for (TypeHandler typeHandler : this.typeHandlers) {
      configuration.getTypeHandlerRegistry().register(typeHandler);
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Registered type handler: '" + typeHandler + "'");
      }
    }
  }
 
  if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
    try {
      configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
    } catch (SQLException e) {
      throw new NestedIOException("Failed getting a databaseId", e);
    }
  }
 
  if (this.cache != null) {
    configuration.addCache(this.cache);
  }
 
  if (xmlConfigBuilder != null) {
    try {
      xmlConfigBuilder.parse();
 
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
      }
    } catch (Exception ex) {
      throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
    } finally {
      ErrorContext.instance().reset();
    }
  }
 
    // 看到事务了
  if (this.transactionFactory == null) {
    this.transactionFactory = new SpringManagedTransactionFactory();
  }
 
  configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
 
 
  if (!isEmpty(this.mapperLocations)) {
    for (Resource mapperLocation : this.mapperLocations) {
      if (mapperLocation == null) {
        continue;
      }
 
      try {
    // 这里是解析mapper.xml文件,将每一个select/update/insert/delete节点都解析成一个MappedStatement,包括了需要执行的sql、输入参数类型、输出参数类型等。
    // MappedStatement的id是namespace加上select/update/insert/delete节点的id,正好对应包名+类名+方法名
    // 所有的MapperStatement都会保存在Configuration中的mappedStatements,是一个Map,在后续sql执行过程中会用到
    // 同时会在configuration中的mapperRegistry中增加对应mapper类型的MapperProxyFactory,在最后生成mapper代理时会用到
        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
            configuration, mapperLocation.toString(), configuration.getSqlFragments());
        xmlMapperBuilder.parse();
      } catch (Exception e) {
        throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
      } finally {
        ErrorContext.instance().reset();
      }
 
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
      }
    }
  } else {
    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
    }
  }
    // 返回一个DefaultSqlSessionFactory
  return this.sqlSessionFactoryBuilder.build(configuration);
}

MybatisAutoConfiguration中也加载了SqlSessionTemplate,SqlSessionTemplate实现了SqlSession

@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);
  }
}

ExecutorType有三种,
simple:普通类型的执行器
reuse:会重用预编译语句
batch:会重用预编译语句,而且可以批量执行
如果我们不指定,默认就是simple

mapper的加载
mapper接口的扫描有2种方式,和我们的写法有关
第一种是在启动类上加上@MapperScan注解,指定mapper所在的包
第二种是不用MapperScan,在mapper接口上用@Mapper注解标注
不过最终扫描mapper干活的都是同一批人,ClassPathMapperScanner

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {

MapperScan注解Import了MapperScannerRegistrar,MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar,在启动过程中会调用registerBeanDefinitions

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 
    // 获取我们启动类上的MapperScan注解
  AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
  ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
 
  // this check is needed in Spring 3.1
  if (resourceLoader != null) {
    scanner.setResourceLoader(resourceLoader);
  }
 
  Class annotationClass = annoAttrs.getClass("annotationClass");
  if (!Annotation.class.equals(annotationClass)) {
    scanner.setAnnotationClass(annotationClass);
  }
 
  Class markerInterface = annoAttrs.getClass("markerInterface");
  if (!Class.class.equals(markerInterface)) {
    scanner.setMarkerInterface(markerInterface);
  }
 
  Class generatorClass = annoAttrs.getClass("nameGenerator");
  if (!BeanNameGenerator.class.equals(generatorClass)) {
    scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
  }
 
  Class mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
  if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
    scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
  }
 
  scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
  scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
 
    // 对应MapperScan注解的value
  List basePackages = new ArrayList();
  for (String pkg : annoAttrs.getStringArray("value")) {
    if (StringUtils.hasText(pkg)) {
      basePackages.add(pkg);
    }
  }
  for (String pkg : annoAttrs.getStringArray("basePackages")) {
    if (StringUtils.hasText(pkg)) {
      basePackages.add(pkg);
    }
  }
  for (Class clazz : annoAttrs.getClassArray("basePackageClasses")) {
    basePackages.add(ClassUtils.getPackageName(clazz));
  }
    // 注册过滤器
  scanner.registerFilters();
    // 包扫描
  scanner.doScan(StringUtils.toStringArray(basePackages));
}

org.mybatis.spring.mapper.ClassPathMapperScanner#registerFilters

public void registerFilters() {
  boolean acceptAllInterfaces = true;
 
    // 指定需要扫描的注解是@Mapper
  // if specified, use the given annotation and / or marker interface
  if (this.annotationClass != null) {
    addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
    acceptAllInterfaces = false;
  }
 
    // 对特定接口的处理
  // override AssignableTypeFilter to ignore matches on the actual marker interface
  if (this.markerInterface != null) {
    addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
      @Override
      protected boolean matchClassName(String className) {
        return false;
      }
    });
    acceptAllInterfaces = false;
  }
 
    // acceptAllInterfaces,为true的话所有的接口都会被加进来
  if (acceptAllInterfaces) {
    // default include filter that accepts all classes
    addIncludeFilter(new TypeFilter() {
      @Override
      public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        return true;
      }
    });
  }
 
    // 排除package-info结尾的接口
  // exclude package-info.java
  addExcludeFilter(new TypeFilter() {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
      String className = metadataReader.getClassMetadata().getClassName();
      return className.endsWith("package-info");
    }
  });
}

org.mybatis.spring.mapper.ClassPathMapperScanner#doScan

@Override
public Set doScan(String... basePackages) {
    // 扫描mapper接口的逻辑
  Set beanDefinitions = super.doScan(basePackages);
 
  if (beanDefinitions.isEmpty()) {
    logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
  } else {
    // 这里有一句话很重要definition.setBeanClass(this.mapperFactoryBean.getClass());
    processBeanDefinitions(beanDefinitions);
  }
 
  return beanDefinitions;
}

// mapperFactoryBean是一个FactoryBean,在Spring初始化的过程中,getBean会触发FactoryBean的getObject方法(以后有时间再看)
org.mybatis.spring.mapper.MapperFactoryBean#getObject

@Override
public T getObject() throws Exception {
    // 这里是sqlSession是DefaultSqlSession
  return getSqlSession().getMapper(this.mapperInterface);
}

// org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper

@Override
public  T getMapper(Class type) {
  return configuration.getMapper(type, this);
}
 
// org.apache.ibatis.session.Configuration#getMapper
public  T getMapper(Class type, SqlSession sqlSession) {
  return mapperRegistry.getMapper(type, sqlSession);
}
 
// org.apache.ibatis.binding.MapperRegistry#getMapper
public  T getMapper(Class type, SqlSession sqlSession) {
  final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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);
  }
}

org.apache.ibatis.binding.MapperProxyFactory#newInstance
(org.apache.ibatis.session.SqlSession)

public T newInstance(SqlSession sqlSession) {
    // 所以最后在service层中操作的mapper对象,就是MapperProxy类型的一个jdk代理
  final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}
 
 
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy mapperProxy) {
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

你可能感兴趣的:(2、MyBatis初始化过程)