当前位置:   article > 正文

Mybatis-Spring原理_springboot生成sqlsessionfactroy过程

springboot生成sqlsessionfactroy过程

一、@MapperScan(basePackages = { "com.uenpay.wfb.repository" })

MapperScan注解中有 @Import(MapperScannerRegistrar.class),MapperScannerRegistrar实现了接口ImportBeanDefinitionRegistrar

通过MapperScannerRegistrar执行registerBeanDefinitions方法,扫描basePackages路径下的包,并把对应的mapper接口注入到spring的初始容器BeanDefinition,不过需要注意的是,这些接口的BeanDefinition的属性beanClass是 org.mybatis.spring.mapper.MapperFactoryBean

这一阶段就完成了mapper接口的初始注入

二、配置类 MybatisAutoConfiguration

  • mybatis-spring-boot-autoconfigure 包里有一个配置文件spring.factories里面包含配置类 MybatisAutoConfiguration

  • springboot由于自动装配原理,会自动加载mybatis的配置类 MybatisAutoConfiguration,配置类中会完成@Bean注解的实例化,并且创建了SqlSessionFactoryBean对象,SqlSessionFactoryBean是实现了FactoryBean接口的,下面执行了factory.getObject()方法

  • getObject()

  1. @Override
  2. public SqlSessionFactory getObject() throws Exception {
  3. if (this.sqlSessionFactory == null) {
  4. afterPropertiesSet();
  5. }
  6. return this.sqlSessionFactory;
  7. }
  • afterPropertiesSet()方法中会执行buildSqlSessionFactory()

  1. protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
  2. Configuration configuration;
  3. XMLConfigBuilder xmlConfigBuilder = null;
  4. if (this.configuration != null) {
  5. configuration = this.configuration;
  6. if (configuration.getVariables() == null) {
  7. configuration.setVariables(this.configurationProperties);
  8. } else if (this.configurationProperties != null) {
  9. configuration.getVariables().putAll(this.configurationProperties);
  10. }
  11. } else if (this.configLocation != null) {
  12. xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
  13. configuration = xmlConfigBuilder.getConfiguration();
  14. } else {
  15. if (LOGGER.isDebugEnabled()) {
  16. LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
  17. }
  18. configuration = new Configuration();
  19. if (this.configurationProperties != null) {
  20. configuration.setVariables(this.configurationProperties);
  21. }
  22. }
  23. if (this.objectFactory != null) {
  24. configuration.setObjectFactory(this.objectFactory);
  25. }
  26. if (this.objectWrapperFactory != null) {
  27. configuration.setObjectWrapperFactory(this.objectWrapperFactory);
  28. }
  29. if (this.vfs != null) {
  30. configuration.setVfsImpl(this.vfs);
  31. }
  32. if (hasLength(this.typeAliasesPackage)) {
  33. String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
  34. ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
  35. for (String packageToScan : typeAliasPackageArray) {
  36. configuration.getTypeAliasRegistry().registerAliases(packageToScan,
  37. typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
  38. if (LOGGER.isDebugEnabled()) {
  39. LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
  40. }
  41. }
  42. }
  43. if (!isEmpty(this.typeAliases)) {
  44. for (Class<?> typeAlias : this.typeAliases) {
  45. configuration.getTypeAliasRegistry().registerAlias(typeAlias);
  46. if (LOGGER.isDebugEnabled()) {
  47. LOGGER.debug("Registered type alias: '" + typeAlias + "'");
  48. }
  49. }
  50. }
  51. if (!isEmpty(this.plugins)) {
  52. for (Interceptor plugin : this.plugins) {
  53. configuration.addInterceptor(plugin);
  54. if (LOGGER.isDebugEnabled()) {
  55. LOGGER.debug("Registered plugin: '" + plugin + "'");
  56. }
  57. }
  58. }
  59. if (hasLength(this.typeHandlersPackage)) {
  60. String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
  61. ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
  62. for (String packageToScan : typeHandlersPackageArray) {
  63. configuration.getTypeHandlerRegistry().register(packageToScan);
  64. if (LOGGER.isDebugEnabled()) {
  65. LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");
  66. }
  67. }
  68. }
  69. if (!isEmpty(this.typeHandlers)) {
  70. for (TypeHandler<?> typeHandler : this.typeHandlers) {
  71. configuration.getTypeHandlerRegistry().register(typeHandler);
  72. if (LOGGER.isDebugEnabled()) {
  73. LOGGER.debug("Registered type handler: '" + typeHandler + "'");
  74. }
  75. }
  76. }
  77. if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
  78. try {
  79. configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
  80. } catch (SQLException e) {
  81. throw new NestedIOException("Failed getting a databaseId", e);
  82. }
  83. }
  84. if (this.cache != null) {
  85. configuration.addCache(this.cache);
  86. }
  87. if (xmlConfigBuilder != null) {
  88. try {
  89. // 解析mybatis-config.xml配置
  90. xmlConfigBuilder.parse();
  91. if (LOGGER.isDebugEnabled()) {
  92. LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
  93. }
  94. } catch (Exception ex) {
  95. throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
  96. } finally {
  97. ErrorContext.instance().reset();
  98. }
  99. }
  100. if (this.transactionFactory == null) {
  101. this.transactionFactory = new SpringManagedTransactionFactory();
  102. }
  103. configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
  104. if (!isEmpty(this.mapperLocations)) {
  105. for (Resource mapperLocation : this.mapperLocations) {
  106. if (mapperLocation == null) {
  107. continue;
  108. }
  109. try {
  110. // 解析 Mapper.xml文件,并封装成MappedStatement对象保存到Configuration
  111. XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
  112. configuration, mapperLocation.toString(), configuration.getSqlFragments());
  113. xmlMapperBuilder.parse();
  114. } catch (Exception e) {
  115. throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
  116. } finally {
  117. ErrorContext.instance().reset();
  118. }
  119. if (LOGGER.isDebugEnabled()) {
  120. LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
  121. }
  122. }
  123. } else {
  124. if (LOGGER.isDebugEnabled()) {
  125. LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
  126. }
  127. }
  128. return this.sqlSessionFactoryBuilder.build(configuration);
  129. }

三、SqlSessionFactory

  • SqlSessionFactory 初始化过程包括: SqlSessionFactoryBean 的加载 及 执行 他的 getObject()方法,该方法的主要逻辑功能时加载 mybatis的配置类 mybatis-config.xml 和 一些mapper.xml文件
  • 加载 mapper.xml 解析一些标签和sql语句 并封装成 MappedStatement 对象放到 Configuration的map集合中,其中key是mapper.xml文件中增删改查标签中的id

四、生成代理Bean

        在生成mapper bean实例时,和其他Bean实例方式差不多,只不过应为mapper是接口,而他的beanClass属性是 org.mybatis.spring.mapper.MapperFactoryBean,所以对于其他常规bean还是有区别的,他会走FactoryBean的路线,通过factoryBean.getObject()返回代理对象,这里用到的是JDK动态代理,生成后填充到spring容器中。

代理几个关键的类

  • MapperFactoryBean

  • MapperProxyFactory
  1. public class MapperProxyFactory<T> {
  2. private final Class<T> mapperInterface;
  3. private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
  4. public MapperProxyFactory(Class<T> mapperInterface) {
  5. this.mapperInterface = mapperInterface;
  6. }
  7. public Class<T> getMapperInterface() {
  8. return mapperInterface;
  9. }
  10. public Map<Method, MapperMethod> getMethodCache() {
  11. return methodCache;
  12. }
  13. @SuppressWarnings("unchecked")
  14. protected T newInstance(MapperProxy<T> mapperProxy) {
  15. return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  16. }
  17. public T newInstance(SqlSession sqlSession) {
  18. final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  19. return newInstance(mapperProxy);
  20. }
  21. }
  • MapperProxy
  1. public class MapperProxy<T> implements InvocationHandler, Serializable {
  2. private static final long serialVersionUID = -6424540398559729838L;
  3. private final SqlSession sqlSession;
  4. private final Class<T> mapperInterface;
  5. private final Map<Method, MapperMethod> methodCache;
  6. public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
  7. this.sqlSession = sqlSession;
  8. this.mapperInterface = mapperInterface;
  9. this.methodCache = methodCache;
  10. }
  11. @Override
  12. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  13. if (Object.class.equals(method.getDeclaringClass())) {
  14. try {
  15. return method.invoke(this, args);
  16. } catch (Throwable t) {
  17. throw ExceptionUtil.unwrapThrowable(t);
  18. }
  19. }
  20. final MapperMethod mapperMethod = cachedMapperMethod(method);
  21. return mapperMethod.execute(sqlSession, args);
  22. }
  23. private MapperMethod cachedMapperMethod(Method method) {
  24. MapperMethod mapperMethod = methodCache.get(method);
  25. if (mapperMethod == null) {
  26. mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
  27. methodCache.put(method, mapperMethod);
  28. }
  29. return mapperMethod;
  30. }
  31. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/949647
推荐阅读
相关标签
  

闽ICP备14008679号