分享

spring集成mybatis配置与源码解析

 我心永恒lz 2017-10-09

1.配置

spring配置文件中添加如下配置:

<!-- SqlSessionFactory bean配置。configurationconfigLocation可以选择其中一个配置,

若都配置了则使用configuration配置,若都不配置使用默认配置-->

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

    <property name="dataSource" ref="dataSource"/>

    <!--配置方式:setter注入-->

    <property name="configuration" ref="configuration"/>

    <!--配置方式:配置文件-->

    <property name="configLocation" value="classpath:config/mybatis-config.xml"/>

    <property name="mapperLocations" value="classpath:com/wxyh/study/dao/**/*.xml"/>

    <!--注入其他属性-->

</bean>

<!-- springmybatis整合配置,扫描所有dao -->

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

    <property name="basePackage" value="com.wxyh.study.dao.**.mapper"/>

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

</bean>

    

2.SqlSessionFactoryBean源码解析

public class SqlSessionFactoryBean implements FactoryBean, InitializingBean,

ApplicationListener {

  

  // 核心字段,这些属性都提供了setter注入方法

  private Resource configLocation;

  private Configuration configuration;

  private Resource[] mapperLocations;

  private DataSource dataSource;

  private TransactionFactory transactionFactory;

  private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

  private SqlSessionFactory sqlSessionFactory;

  private String environment = SqlSessionFactoryBean.class.getSimpleName();

  private boolean failFast;

  private Interceptor[] plugins;

  private TypeHandler[] typeHandlers;

  private String typeHandlersPackage;

  private Class[] typeAliases;

  private String typeAliasesPackage;

  private Class typeAliasesSuperType;

  private DatabaseIdProvider databaseIdProvider;

  private Class vfs;

  private Cache cache;

  private ObjectFactory objectFactory;

  private ObjectWrapperFactory objectWrapperFactory;


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

  }

 

   protected SqlSessionFactory buildSqlSessionFactory() throws IOException {

 

    Configuration configuration;

    XMLConfigBuilder xmlConfigBuilder = null;

    if (this.configuration != null) {

      // 注入了configuration bean,优先使用

      configuration = this.configuration;

      if (configuration.getVariables() == null) {

        configuration.setVariables(this.configurationProperties);

      } else if (this.configurationProperties != null) {

        configuration.getVariables().putAll(this.configurationProperties);

      }

    } else if (this.configLocation != null) {

      // 有配置文件,后面会解析配置文件,把相关配置保存在configuration

      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");

      }

      // 没有配置configurationconfigLocation,使用默认配置

      configuration = new Configuration();

      if (this.configurationProperties != null) {

        configuration.setVariables(this.configurationProperties);

      }

    }

 

    // 略去设置或解析setter注入属性代码,有

    // objectFactory,objectWrapperFactory,vfs,typeAliasesPackage,typeAliases,

    // plugins,typeHandlersPackage,typeHandlers,databaseIdProvider,cache

    ......

 

    if (xmlConfigBuilder != null) {

      try {

// 解析配置文件mybatis-config.xml

// 详细源码解析见:http://www.360doc.com/content/17/0929/23/21706453_691232980.shtml

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

    

    // 解析mapperLocations指定mapper配置文件

    if (!isEmpty(this.mapperLocations)) {

      for (Resource mapperLocation : this.mapperLocations) {

        if (mapperLocation == null) {

          continue;

        }

        try {

  // 逐个解析mapper配置文件,

  // 解析源码见:http://www.360doc.com/content/17/0929/23/21706453_691232980.shtml (4.2)

    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");

      }

    }

 

    // 构建sqlSessionFactory对象

    return this.sqlSessionFactoryBuilder.build(configuration);

  }

 

  @Override

  public SqlSessionFactory getObject() throws Exception {

    if (this.sqlSessionFactory == null) {

      afterPropertiesSet();

    }

 

    return this.sqlSessionFactory;

  }

 

}

 

SqlSessionFactoryBeanSqlSessionFactory的工厂bean

启动项目时spring首先会创建SqlSessionFactoryBean对象,然后会把getObject()的返回值DefaultSqlSessionFactory对象作为bean注册到容器中。

 

3.MapperScannerConfigurer源码解析

 

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor,

InitializingBean, ApplicationContextAware, BeanNameAware {

 

  // 核心字段,这些属性都提供了setter注入方法

  private String basePackage;

  private boolean addToConfig = true;

  private SqlSessionFactory sqlSessionFactory;

  private SqlSessionTemplate sqlSessionTemplate;

  private String sqlSessionFactoryBeanName;

  private String sqlSessionTemplateBeanName;

  // mapper接口使用的注解类型

  private Class annotationClass;

  // mapper接口的父接口类型

  private Class markerInterface;

  private ApplicationContext applicationContext;

  private String beanName;

  private boolean processPropertyPlaceHolders;

  private BeanNameGenerator nameGenerator;

 

  @Override

  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {

    if (this.processPropertyPlaceHolders) {

      processPropertyPlaceHolders();

    }

 

    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);

    scanner.setAddToConfig(this.addToConfig);

    // 设置mapper接口使用的注解或父类型

    scanner.setAnnotationClass(this.annotationClass);

    scanner.setMarkerInterface(this.markerInterface);

    scanner.setSqlSessionFactory(this.sqlSessionFactory);

    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);

    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);

    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);

    scanner.setResourceLoader(this.applicationContext);

    scanner.setBeanNameGenerator(this.nameGenerator);

    // 配置过滤basePackage包中mapper接口的规则,源码分析见4

    scanner.registerFilters();

    // 扫描basePackage包中mapper接口,将其封装为MapperFactoryBean

    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));

  }

 

  ......

 

}

 

4.ClassPathMapperScanner源码解析

 

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

  

  // 核心字段,这些属性都提供了setter注入方法

  private boolean addToConfig = true;

  private SqlSessionFactory sqlSessionFactory;

  private SqlSessionTemplate sqlSessionTemplate;

  private String sqlSessionTemplateBeanName;

  private String sqlSessionFactoryBeanName;

  private Class annotationClass;

  private Class markerInterface;

  private MapperFactoryBean mapperFactoryBean = new MapperFactoryBean();

 

  /**

   * 配置扫描器以注册basePackage包中正确的接口为mapper

   */

  public void registerFilters() {

    boolean acceptAllInterfaces = true;

 

    // basePackage包中有annotationClass类型注解的所有接口注册为mapper

    if (this.annotationClass != null) {

      addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));

      acceptAllInterfaces = false;

    }

 

    // basePackage包中派生自markerInterface类型接口的所有接口注册为mapper

    // 重写matchClassName方法,以免注册markerInterface接口为mapper

    if (this.markerInterface != null) {

      addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {

        @Override

        protected boolean matchClassName(String className) {

          return false;

        }

      });

      acceptAllInterfaces = false;

    }

 

    if (acceptAllInterfaces) {

      // 如果没有设置annotationClassmarkerInterface,则注册basePackage包中所有类为mapper

      // default include filter that accepts all classes

      addIncludeFilter(new TypeFilter() {

        @Override

        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {

          return true;

        }

      });

    }

 

    // 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");

      }

    });

  }

 

  /**

   * Calls the parent search that will search and register all the candidates.

   * Then the registered objects are post processed to set them as

   * MapperFactoryBeans

   */

  @Override

  public Set doScan(String... basePackages) {

    // 调用父类方法,扫描basePackages包中的mapper接口,返回BeanDefinitionHolder集合

    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 {

      processBeanDefinitions(beanDefinitions);

    }

 

    return beanDefinitions;

  }

 

  /**

   * 定义mapper的工厂bean MapperFactoryBean

   */

  private void processBeanDefinitions(Set beanDefinitions) {

    GenericBeanDefinition definition;

    for (BeanDefinitionHolder holder : beanDefinitions) {

      definition = (GenericBeanDefinition) holder.getBeanDefinition();

 

      if (logger.isDebugEnabled()) {

        logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()

          + "' and '" + definition.getBeanClassName() + "' mapperInterface");

      }

 

      // the mapper interface is the original class of the bean

      // but, the actual class of the bean is MapperFactoryBean

      // 通过构造函数传参设置MapperFactoryBean所生产bean的类型

      definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59

      definition.setBeanClass(this.mapperFactoryBean.getClass());

 

      definition.getPropertyValues().add("addToConfig", this.addToConfig);

 

      // MapperFactoryBean注入sqlSessionFactory

      boolean explicitFactoryUsed = false;

      if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {

        definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));

        explicitFactoryUsed = true;

      } else if (this.sqlSessionFactory != null) {

        definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);

        explicitFactoryUsed = true;

      }

 

      // MapperFactoryBean注入sqlSessionTemplate.

      // 如果已注入sqlSessionFactory则忽略该配置,使用sqlSessionTemplate,详见源码

      if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {

        if (explicitFactoryUsed) {

          logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");

        }

        definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));

        explicitFactoryUsed = true;

      } else if (this.sqlSessionTemplate != null) {

        if (explicitFactoryUsed) {

          logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");

        }

        definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);

        explicitFactoryUsed = true;

      }

 

      if (!explicitFactoryUsed) {

        if (logger.isDebugEnabled()) {

          logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");

        }

        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

      }

    }

  }

 

}

 

5.MapperFactoryBean源码解析

 

public class MapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean {

 

  // mapper bean的类型

  private Class mapperInterface;

  // true,添加mapperMapperRegistry

  private boolean addToConfig = true;

 

  public MapperFactoryBean() {

    //intentionally empty

  }

  

  public MapperFactoryBean(Class mapperInterface) {

    this.mapperInterface = mapperInterface;

  }

 

  @Override

  protected void checkDaoConfig() {

    super.checkDaoConfig();

 

    notNull(this.mapperInterface, "Property 'mapperInterface' is required");

 

    Configuration configuration = getSqlSession().getConfiguration();

    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {

      try {

        // 添加mapperMapperRegistry,源码分析见xxxxxxxxxxx

        configuration.addMapper(this.mapperInterface);

      } catch (Exception e) {

        logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);

        throw new IllegalArgumentException(e);

      } finally {

        ErrorContext.instance().reset();

      }

    }

  }

 

  @Override

  public T getObject() throws Exception {

    // getSqlSession()返回的是一个SqlSessionTemplate对象

    // getMapper方法从MapperRegistry中获取的是MapperProxyFactory对象

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

  }

 

}

 

public abstract class SqlSessionDaoSupport extends DaoSupport {

 

  // 通过sqlSessionFactorysqlSessionTemplate,生成的sqlSession对象都是SqlSessionTemplate类型,

  // 实际上是SqlSession的代理对象

  private SqlSession sqlSession;

  private boolean externalSqlSession;

 

  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {

    if (!this.externalSqlSession) {

      // 如果设置了sqlSessionTemplate,则不再使用sqlSessionFactory

      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);

    }

  }

 

  public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {

    this.sqlSession = sqlSessionTemplate;

    this.externalSqlSession = true;

  }

 

  /**

   * Users should use this method to get a SqlSession to call its statement methods

   * This is SqlSession is managed by spring. Users should not commit/rollback/close it

   * because it will be automatically done.

   *

   * @return Spring managed thread safe SqlSession

   */

  public SqlSession getSqlSession() {

    return this.sqlSession;

  }

 

  @Override

  protected void checkDaoConfig() {

    notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");

  }

 

}

 

6.SqlSessionTemplate源码解析

 

public class SqlSessionTemplate implements SqlSession, DisposableBean {

 

  private final SqlSessionFactory sqlSessionFactory;

  private final ExecutorType executorType;

  // SqlSession的代理对象

  private final SqlSession sqlSessionProxy;

  private final PersistenceExceptionTranslator exceptionTranslator;

 

  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {

    this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());

  }

 

  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {

    this(sqlSessionFactory, executorType,

        new MyBatisExceptionTranslator(

            sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));

  }

 

  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,

      PersistenceExceptionTranslator exceptionTranslator) {

 

    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");

    notNull(executorType, "Property 'executorType' is required");

 

    this.sqlSessionFactory = sqlSessionFactory;

    this.executorType = executorType;

    this.exceptionTranslator = exceptionTranslator;

   // 创建sqlSession的代理对象,调用sqlSession的所有方法,都被SqlSessionInterceptorinvoke方法拦截

    this.sqlSessionProxy = (SqlSession) newProxyInstance(

        SqlSessionFactory.class.getClassLoader(),

        new Class[] { SqlSession.class },

        new SqlSessionInterceptor());

  }

 

  /**

   * 内部类

   * jdk动态代理拦截器类

   */

  private class SqlSessionInterceptor implements InvocationHandler {

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

      SqlSession sqlSession = getSqlSession(

          SqlSessionTemplate.this.sqlSessionFactory,

          SqlSessionTemplate.this.executorType,

          SqlSessionTemplate.this.exceptionTranslator);

      try {

        Object result = method.invoke(sqlSession, args);

        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {

          // force commit even on non-dirty sessions because some databases require

          // a commit/rollback before calling close()

          sqlSession.commit(true);

        }

        return result;

      } catch (Throwable t) {

        Throwable unwrapped = unwrapThrowable(t);

        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {

          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22

          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);

          sqlSession = null;

          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);

          if (translated != null) {

            unwrapped = translated;

          }

        }

        throw unwrapped;

      } finally {

        if (sqlSession != null) {

          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);

        }

      }

    }

  }

 

}

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多