spring(boot) mybatis整合


1.Mybatis解析配置部分

下圖是解析配置類的UML圖

 

SqlSessionFactoryBuilder

 1 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
 2     try {
 3       XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
 4       return build(parser.parse());
 5     } catch (Exception e) {
 6       throw ExceptionFactory.wrapException("Error building SqlSession.", e);
 7     } finally {
 8       ErrorContext.instance().reset();
 9       try {
10         inputStream.close();
11       } catch (IOException e) {
12         // Intentionally ignore. Prefer previous error.
13       }
14     }
15   }
16     
17   public SqlSessionFactory build(Configuration config) {
18     return new DefaultSqlSessionFactory(config);
19   }

XMLConfigBuilder負責解析配置文件,XMLConfigBuilder會調用XPathParser 產生Configuration對象,XPathParser 利用XPath技術解析XMLConfiguration里面存儲的都是config配置文件各種信息,我們也可以編程自己實例化Configuration來創建SqlSessionFactory

還有類MapperAnnotationBuilder是用來解析注解配置Mapper

 

XMLMapperBuilder是用來解析Xml配置Mapper

2.Spring整合Mybatis

SqlSessionFactoryBean

 

MapperFactoryBean

 

 

SqlSessionFactoryBean

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

Spring整合Mybatis最重要的是上面兩個FactoryBeanFactoryBeanSpring一種特殊的BeanSpring會調用getObject方法產生Bean

 

現在簡單看下SqlSessionFactoryBean 源碼,看源碼最后會調用到方法buildSqlSessionFactory,在下面源碼我們看到了熟悉的幾個類XMLConfigBuilderConfigurationSqlSessionFactoryBuilderSqlSessionFactoryXMLMapperBuilder(解析XmlMapper,注解的MapperMapperFactoryBean

 

 1 protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
 2 
 3     Configuration configuration;
 4 
 5     XMLConfigBuilder xmlConfigBuilder = null;
 6     if (this.configuration != null) {
 7       configuration = this.configuration;
 8       if (configuration.getVariables() == null) {
 9         configuration.setVariables(this.configurationProperties);
10       } else if (this.configurationProperties != null) {
11         configuration.getVariables().putAll(this.configurationProperties);
12       }
13 //如果配置了configLocation,則直接調用XMLConfigBuilder得到Configuration
14     } else if (this.configLocation != null) {
15       xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
16       configuration = xmlConfigBuilder.getConfiguration();
17 } else {
18 //如果沒有配置configLocation,先直接new Configuration 
19       if (LOGGER.isDebugEnabled()) {
20         LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
21       }
22       configuration = new Configuration();
23       if (this.configurationProperties != null) {
24         configuration.setVariables(this.configurationProperties);
25       }
26     }
27 //配置前面得到的Configuration,Configuration的set設置都是FactoryBean的配置屬性
28    //……. objectFactory
29 
30    //……objectWrapperFactory
31 
32    //………. vfs
33 
34    //………typeAliasesPackage
35 
36     //……….. typeAliases
37 
38    //……………plugins
39 
40     //…………typeHandlersPackage
41 
42   //…………typeHandlers
43 
44   //…………. databaseIdProvider
45 
46  //……………….cache
47 
48 //配置了configLocation的時候解析
49     if (xmlConfigBuilder != null) {
50       try {
51         xmlConfigBuilder.parse();
52 
53         if (LOGGER.isDebugEnabled()) {
54           LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
55         }
56       } catch (Exception ex) {
57         throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
58       } finally {
59         ErrorContext.instance().reset();
60       }
61     }
62 //沒有配置transactionFactory   默認指定SpringManagedTransactionFactory
63     if (this.transactionFactory == null) {
64       this.transactionFactory = new SpringManagedTransactionFactory();
65     }
66 
67 configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
68 
69     if (!isEmpty(this.mapperLocations)) {
70       for (Resource mapperLocation : this.mapperLocations) {
71         if (mapperLocation == null) {
72           continue;
73         }
74 //解析XmlMapper,如果配置了mapperLocations
75         try {
76           XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
77               configuration, mapperLocation.toString(), configuration.getSqlFragments());
78           xmlMapperBuilder.parse();
79         } catch (Exception e) {
80           throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
81         } finally {
82           ErrorContext.instance().reset();
83         }
84 
85         if (LOGGER.isDebugEnabled()) {
86           LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
87         }
88       }
89     } else {
90       if (LOGGER.isDebugEnabled()) {
91         LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
92       }
93     }
94 
95     return this.sqlSessionFactoryBuilder.build(configuration);
96   }

 

MapperFactoryBean

1 <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
2   <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
3   <property name="sqlSessionFactory" ref="sqlSessionFactory" />
4 </bean>

這個是處理注解的Mapper,簡單的看下他的getObject方法,先看下這個類的簽名,在看它的getObject方法

public class MapperFactoryBean<T> extends SqlSessionDaoSupport

public T getObject() throws Exception {

    return getSqlSession().getMapper(this.mapperInterface);

  }

 

這個是注解Mapper的正常用法。

MapperScannerConfigurer

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>

這個這個類會更具指定的basePackage來自動裝配MapperFactoryBean,但如果指定了多個DataSource,則必須指定 sqlSessionFactoryBeanName屬性

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

SqlSessionTemplate

SqlSessionDaoSupport

 

上面兩個類是Spring對於Mybatis DAO支持的具體實現類

3SpringBoot整合Mybatis

mybatis-spring-boot-starter來進行pom更新來支持mybatis starter開發,分析Spring Boot知道,AutoConfigurationstarter的核心,boot加載的時候會讀取classpath下的spring.factories,下面是MybatisAutoConfiguration配置

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

 

可以看到類org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

現在看下這個類的簽名

@org.springframework.context.annotation.Configuration

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })

@ConditionalOnBean(DataSource.class)

@EnableConfigurationProperties(MybatisProperties.class)

 

@AutoConfigureAfter(DataSourceAutoConfiguration.class)

publicclass MybatisAutoConfiguration {……..}

Configuration注解:說明這是spring的配置項,容器初始化的時候要進行解析處理

ConditionalOnClass注解:有類SqlSessionFactory(Mybatis)SqlSessionFactoryBean(Mybatis-Spring)的時候才進行解析處理

ConditionalOnBean:容器中有DataSource Bean的時候才進行解析處理

AutoConfigureAfter注解: DataSourceAutoConfiguration后解析

EnableConfigurationProperties注解和MybatisProperties:配置自己的Mybatis 屬性,在Application.Properties中。

 

MybatisAutoConfiguration源碼,幾點

1.  SqlSessionFactory

@Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource){…………….}
實例化SqlSessionFactory bean

2.  sqlSessionTemplate

@Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory){………………}

3.  MapperScannerRegistrarNotFoundConfiguration

 1 @org.springframework.context.annotation.Configuration
 2   @Import({ AutoConfiguredMapperScannerRegistrar.class })
 3   @ConditionalOnMissingBean(MapperFactoryBean.class)
 4   public static class MapperScannerRegistrarNotFoundConfiguration {
 5 
 6     @PostConstruct
 7     public void afterPropertiesSet() {
 8       logger.debug("No {} found.", MapperFactoryBean.class.getName());
 9     }
10   }

如果沒有使用MapperScann這個注解,會自動去搜索Mapper,看下源碼,Import注解里面的類才是關鍵AutoConfiguredMapperScannerRegistrar,看他的registerBeanDefinitions方法源碼,發現它會去類路徑下去搜索Mapper注解的類生成MapperFactoryBean

 1 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 2 
 3       logger.debug("Searching for mappers annotated with @Mapper");
 4 
 5       ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
 6 
 7       try {
 8         if (this.resourceLoader != null) {
 9           scanner.setResourceLoader(this.resourceLoader);
10         }
11 
12         List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
13         if (logger.isDebugEnabled()) {
14           for (String pkg : packages) {
15             logger.debug("Using auto-configuration base package '{}'", pkg);
16           }
17         }
18 
19         scanner.setAnnotationClass(Mapper.class);
20         scanner.registerFilters();
21         scanner.doScan(StringUtils.toStringArray(packages));
22       } catch (IllegalStateException ex) {
23         logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
24       }
25 }

最后看下MapperScann注解

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Documented

@Import(MapperScannerRegistrar.class)

public @interface MapperScan {}

 

看類MapperScannerRegistrarregisterBeanDefinitions方法,最后也是借用ClassPathMapperScanner類去掃描Mapper注解

 

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {

    try {

      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);

      return build(parser.parse());

    } catch (Exception e) {

      throw ExceptionFactory.wrapException("Error building SqlSession.", e);

    } finally {

      ErrorContext.instance().reset();

      try {

        inputStream.close();

      } catch (IOException e) {

        // Intentionally ignore. Prefer previous error.

      }

    }

  }

   

  public SqlSessionFactory build(Configuration config) {

    returnnew DefaultSqlSessionFactory(config);

  }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM