• MyBatis源码解析(一)


    <!-- mybatis文件配置,扫描所有mapper文件 -->
    <!--
    SqlSessionFactoryBean的初始化参数-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:/spring/mybatis.xml"/>
    
       <property name="typeAliasesPackage" value="com.cloudwalk.shark.model"/>
    
       <property name="mapperLocations" value="classpath*:mapper/*.xml"/>
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageHelper">
                    <property name="properties">
                        <!--使用下面的方式配置参数,一行配置一个 -->
                        <value>
                            dialect=mysql
                        </value>
                    </property>
                </bean>
            </array>
        </property>
    </bean>
    <!-- spring与mybatis整合配置,扫描所有dao,指定的映射器类是接口,接口方法可以用注解来指定 SQL 语句,但是 MyBatis 的映射器 XML 文件也可以用。 -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
              p:basePackage="com.cloudwalk.shark.mapper"
              p:sqlSessionFactoryBeanName="sqlSessionFactory"/>

    下面跟踪SqlSessionFactoryBean.java的源码

    public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
    }

     实现了InitializingBean,ApplicationListener,自然而然就会在Spring加载的过程中做一些操作:

    public void afterPropertiesSet() throws Exception {
            Assert.notNull(this.dataSource, "Property 'dataSource' is required");
            Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
            Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
            this.sqlSessionFactory = this.buildSqlSessionFactory();
        }
    this.buildSqlSessionFactory();这个就是核心重点!!!
     protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
            XMLConfigBuilder xmlConfigBuilder = null;
            Configuration targetConfiguration;
            if (this.configuration != null) {
                targetConfiguration = this.configuration;
                if (targetConfiguration.getVariables() == null) {
                    targetConfiguration.setVariables(this.configurationProperties);
                } else if (this.configurationProperties != null) {
                    targetConfiguration.getVariables().putAll(this.configurationProperties);
                }
            } else if (this.configLocation != null) {
                xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
                targetConfiguration = xmlConfigBuilder.getConfiguration();
            } else {
                LOGGER.debug(() -> {
                    return "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration";
                });
                targetConfiguration = new Configuration();
                Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
            }
    
            Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
            Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
            Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);
            String[] typeHandlersPackageArray;
            if (StringUtils.hasLength(this.typeAliasesPackage)) {
                typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeAliasesPackage, ",; 	
    ");
                Stream.of(typeHandlersPackageArray).forEach((packageToScan) -> {
                    targetConfiguration.getTypeAliasRegistry().registerAliases(packageToScan, this.typeAliasesSuperType == null ? Object.class : this.typeAliasesSuperType);
                    LOGGER.debug(() -> {
                        return "Scanned package: '" + packageToScan + "' for aliases";
                    });
                });
            }
    
            if (!ObjectUtils.isEmpty(this.typeAliases)) {
                Stream.of(this.typeAliases).forEach((typeAlias) -> {
                    targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);
                    LOGGER.debug(() -> {
                        return "Registered type alias: '" + typeAlias + "'";
                    });
                });
            }
    
            if (!ObjectUtils.isEmpty(this.plugins)) {
                Stream.of(this.plugins).forEach((plugin) -> {
                    targetConfiguration.addInterceptor(plugin);
                    LOGGER.debug(() -> {
                        return "Registered plugin: '" + plugin + "'";
                    });
                });
            }
    
            if (StringUtils.hasLength(this.typeHandlersPackage)) {
                typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeHandlersPackage, ",; 	
    ");
                Stream.of(typeHandlersPackageArray).forEach((packageToScan) -> {
                    targetConfiguration.getTypeHandlerRegistry().register(packageToScan);
                    LOGGER.debug(() -> {
                        return "Scanned package: '" + packageToScan + "' for type handlers";
                    });
                });
            }
    
            if (!ObjectUtils.isEmpty(this.typeHandlers)) {
                Stream.of(this.typeHandlers).forEach((typeHandler) -> {
                    targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
                    LOGGER.debug(() -> {
                        return "Registered type handler: '" + typeHandler + "'";
                    });
                });
            }
    
            if (this.databaseIdProvider != null) {
                try {
                    targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
                } catch (SQLException var23) {
                    throw new NestedIOException("Failed getting a databaseId", var23);
                }
            }
    
            Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache);
            if (xmlConfigBuilder != null) {
                try {
                    xmlConfigBuilder.parse();
                    LOGGER.debug(() -> {
                        return "Parsed configuration file: '" + this.configLocation + "'";
                    });
                } catch (Exception var21) {
                    throw new NestedIOException("Failed to parse config resource: " + this.configLocation, var21);
                } finally {
                    ErrorContext.instance().reset();
                }
            }
    
            targetConfiguration.setEnvironment(new Environment(this.environment, (TransactionFactory)(this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory), this.dataSource));
            if (!ObjectUtils.isEmpty(this.mapperLocations)) {
                Resource[] var24 = this.mapperLocations;
                int var4 = var24.length;
    
                for(int var5 = 0; var5 < var4; ++var5) {
                    Resource mapperLocation = var24[var5];
                    if (mapperLocation != null) {
                        try {
                            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
                            xmlMapperBuilder.parse();
                        } catch (Exception var19) {
                            throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", var19);
                        } finally {
                            ErrorContext.instance().reset();
                        }
    
                        LOGGER.debug(() -> {
                            return "Parsed mapper file: '" + mapperLocation + "'";
                        });
                    }
                }
            } else {
                LOGGER.debug(() -> {
                    return "Property 'mapperLocations' was not specified or no matching resources found";
                });
            }
    
            return this.sqlSessionFactoryBuilder.build(targetConfiguration);
        }

    这个方法我们慢慢仔细看:

            XMLConfigBuilder xmlConfigBuilder = null;
            Configuration targetConfiguration;
            if (this.configuration != null) {
                targetConfiguration = this.configuration;
                if (targetConfiguration.getVariables() == null) {
                    targetConfiguration.setVariables(this.configurationProperties);
                } else if (this.configurationProperties != null) {
                    targetConfiguration.getVariables().putAll(this.configurationProperties);
                }
            } else if (this.configLocation != null) {
                xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
                targetConfiguration = xmlConfigBuilder.getConfiguration();
            } else {
                LOGGER.debug(() -> {
                    return "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration";
                });
                targetConfiguration = new Configuration();
                Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
            }

    上面中标红的就是核心代码,

    public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
        this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
      }
    public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
        commonConstructor(validation, variables, entityResolver);
        this.document = createDocument(new InputSource(inputStream));
      }
    private Document createDocument(InputSource inputSource) {
        // important: this must only be called AFTER common constructor
        try {
          DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
          factory.setValidating(validation);
    
          factory.setNamespaceAware(false);
          factory.setIgnoringComments(true);
          factory.setIgnoringElementContentWhitespace(false);
          factory.setCoalescing(false);
          factory.setExpandEntityReferences(true);
    
          DocumentBuilder builder = factory.newDocumentBuilder();
          builder.setEntityResolver(entityResolver);
          builder.setErrorHandler(new ErrorHandler() {
            @Override
            public void error(SAXParseException exception) throws SAXException {
              throw exception;
            }
    
            @Override
            public void fatalError(SAXParseException exception) throws SAXException {
              throw exception;
            }
    
            @Override
            public void warning(SAXParseException exception) throws SAXException {
            }
          });
          return builder.parse(inputSource);
        } catch (Exception e) {
          throw new BuilderException("Error creating document instance.  Cause: " + e, e);
        }
      }
    public Document parse(InputSource is) throws SAXException, IOException {
            if (is == null) {
                throw new IllegalArgumentException(
                    DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
                    "jaxp-null-input-source", null));
            }
            if (fSchemaValidator != null) {
                if (fSchemaValidationManager != null) {
                    fSchemaValidationManager.reset();
                    fUnparsedEntityHandler.reset();
                }
                resetSchemaValidator();
            }
            domParser.parse(is);
            Document doc = domParser.getDocument();
            domParser.dropDocumentReferences();
            return doc;
        }
    configLocation就算解析完成了;其他的
    typeAliasesPackage,plugins都没什么好看的,不过
    plugins中通过添加interceptor完成插件的拦截入口,常用的就是PageHelper分页插件,后面可以具体看看这个是如何生效的!!
     if (!ObjectUtils.isEmpty(this.plugins)) {
                Stream.of(this.plugins).forEach((plugin) -> {
                    targetConfiguration.addInterceptor(plugin);
                    LOGGER.debug(() -> {
                        return "Registered plugin: '" + plugin + "'";
                    });
                });
            }

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
    public class Configuration {
    
      protected Environment environment;
    
      protected boolean safeRowBoundsEnabled = false;
      protected boolean safeResultHandlerEnabled = true;
      protected boolean mapUnderscoreToCamelCase = false;
      protected boolean aggressiveLazyLoading = true;
      protected boolean multipleResultSetsEnabled = true;
      protected boolean useGeneratedKeys = false;
      protected boolean useColumnLabel = true;
      protected boolean cacheEnabled = true;
      protected boolean callSettersOnNulls = false;
      protected boolean useActualParamName = true;
    
      protected String logPrefix;
      protected Class <? extends Log> logImpl;
      protected Class <? extends VFS> vfsImpl;
      protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
      protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
      protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
      protected Integer defaultStatementTimeout;
      protected Integer defaultFetchSize;
      protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
      protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
      protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
    
      protected Properties variables = new Properties();
      protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
      protected ObjectFactory objectFactory = new DefaultObjectFactory();
      protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
    
      protected boolean lazyLoadingEnabled = false;
      protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
    
      protected String databaseId;
      /**
       * Configuration factory class.
       * Used to create Configuration for loading deserialized unread properties.
       *
       * @see <a href='https://code.google.com/p/mybatis/issues/detail?id=300'>Issue 300 (google code)</a>
       */
      protected Class<?> configurationFactory;
    
      protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
      protected final InterceptorChain interceptorChain = new InterceptorChain();
      protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
      protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
      protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
    
      protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
      protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
      protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
      protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");
      protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");
    
      protected final Set<String> loadedResources = new HashSet<String>();
      protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");
    
      protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();
      protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();
      protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();
      protected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>();
    
      /*
       * A map holds cache-ref relationship. The key is the namespace that
       * references a cache bound to another namespace and the value is the
       * namespace which the actual cache is bound to.
       */
      protected final Map<String, String> cacheRefMap = new HashMap<String, String>();
    
      public Configuration(Environment environment) {
        this();
        this.environment = environment;
      }
    
      public Configuration() {
        typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
        typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
    
        typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
        typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
        typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
    
        typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
        typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
        typeAliasRegistry.registerAlias("LRU", LruCache.class);
        typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
        typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
    
        typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
    
        typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
        typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
    
        typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
        typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
        typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
        typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
        typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
        typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
        typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
    
        typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
        typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
    
        languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
        languageRegistry.register(RawLanguageDriver.class);
      }
     
  • 相关阅读:
    Character Encoding题解(容斥)
    P1445 [Violet]樱花 题解(推式子)
    F. Stone 题解(对称博弈)
    M. 810975 题解(容斥)
    P1365 WJMZBMR打osu! / Easy 题解(期望dp)
    icpc济南
    C#创建windows服务并定时执行
    批处理 windows 服务的安装与卸载
    前台单击文件,jQuery删除后台相应真实的文件
    Jquery直接调用后台方法(WebMethod框架的使用)
  • 原文地址:https://www.cnblogs.com/longxok/p/10855691.html
Copyright © 2020-2023  润新知