<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          MyBatis Plus插件機(jī)制與執(zhí)行流程原理分析

          共 20122字,需瀏覽 41分鐘

           ·

          2020-09-10 02:03

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          66套java從入門(mén)到精通實(shí)戰(zhàn)課程分享?

          【1】MyBatis Plus插件

          MyBatis Plus提供了分頁(yè)插件PaginationInterceptor、執(zhí)行分析插件SqlExplainInterceptor、性能分析插件PerformanceInterceptor以及樂(lè)觀鎖插件OptimisticLockerInterceptor。

          Mybatis 通過(guò)插件 (Interceptor) 可以做到攔截四大對(duì)象相關(guān)方法的執(zhí)行 ,根據(jù)需求完成相關(guān)數(shù)據(jù)的動(dòng)態(tài)改變。

          四大對(duì)象是:

          • Executor

          • StatementHandler

          • ParameterHandler

          • ResultSetHandler

          四大對(duì)象的每個(gè)對(duì)象在創(chuàng)建時(shí),都會(huì)執(zhí)行interceptorChain.pluginAll(),會(huì)經(jīng)過(guò)每個(gè)插件對(duì)象的?plugin()方法,目的是為當(dāng)前的四大對(duì)象創(chuàng)建代理。代理對(duì)象就可以攔截到四大對(duì)象相關(guān)方法的執(zhí)行,因?yàn)橐獔?zhí)行四大對(duì)象的方法需要經(jīng)過(guò)代理 。

          ① xml下插件的配置

          如下所示:

          "sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"><property name="dataSource" ref="dataSource">property><property name="configLocation" value="classpath:mybatis-config.xml">property><property name="typeAliasesPackage" value="com.jane.mp.beans">property><property name="globalConfig" ref="globalConfiguration">property><property name="plugins"><list><bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor">bean><bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor"><property name="stopProceed" value="true">property>bean><bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"><property name="format" value="true">property>bean><bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor">bean>list>property>bean>

          ② springboot下注冊(cè)插件

          這里以分頁(yè)插件為例:

          @Bean public PaginationInterceptor paginationInterceptor() {     PaginationInterceptor paginationInterceptor = new PaginationInterceptor();     // 設(shè)置請(qǐng)求的頁(yè)面大于最大頁(yè)后操作, true調(diào)回到首頁(yè),false 繼續(xù)請(qǐng)求  默認(rèn)false     // paginationInterceptor.setOverflow(false);     // 設(shè)置最大單頁(yè)限制數(shù)量,默認(rèn) 500 條,-1 不受限制     // paginationInterceptor.setLimit(500);     // 開(kāi)啟 count 的 join 優(yōu)化,只針對(duì)部分 left join     paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));     return paginationInterceptor;?}

          ③ SqlExplainInterceptor

          SQL執(zhí)行分析攔截器,全類(lèi)名是com.baomidou.mybatisplus.plugins.SqlExplainInterceptor,只支持 MySQL5.6.3以上版本。

          該插件的作用是分析?DELETE UPDATE語(yǔ)句 ,防止小白或者惡意進(jìn)行DELETE UPDATE全表操作,不建議在生產(chǎn)環(huán)境中使用會(huì)造成性能下降,

          在插件的底層通過(guò)SQL語(yǔ)句分析命令?Explain?分析當(dāng)前的 SQL語(yǔ)句,根據(jù)結(jié)果集中的?Extra列來(lái)斷定當(dāng)前是否全表操作。

          ④ 性能分析插件

          性能分析攔截器,全類(lèi)名是com.baomidou.mybatisplus.plugins.PerformanceInterceptor,用于輸出每條 SQL 語(yǔ)句及其執(zhí)行時(shí)間。SQL性能執(zhí)行分析 ,開(kāi)發(fā)環(huán)境使用 超過(guò)指定時(shí)間,停止運(yùn)行。

          ⑤ 樂(lè)觀鎖插件

          全類(lèi)名是com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor。如果想實(shí)現(xiàn)如下需求 : 當(dāng)要更新一條記錄的時(shí)候,希望這條記錄沒(méi)有被別人更新,就可以使用該插件進(jìn)行判斷。

          樂(lè)觀鎖的實(shí)現(xiàn)原理(@Version 用于注解實(shí)體字段,必須要有) :

          • 取出記錄時(shí),獲取當(dāng)前 version

          • 更新時(shí),帶上這個(gè)version

          • 執(zhí)行更新時(shí),set version = yourVersion+1 where version = yourVersion

          • 如果 version不對(duì),就更新失敗

          【2】獲取sqlSessionFactoryBean

          如下圖所示,在系統(tǒng)啟動(dòng)時(shí)會(huì)初始化定義的bean。DefaultListableBeanFactory.preInstantiateSingletons方法中會(huì)從beanDefinitionNames中獲取bean name然后依次創(chuàng)建。

          這里可以看到RootBeanDefinition是com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean

          ① 獲取bean的過(guò)程中bean屬性

          如下所示,在getBean過(guò)程中可以看到bean的屬性:

          ② createBean

          第一次獲取bean的時(shí)候會(huì)走到AbstractAutowireCapableBeanFactory.createBean進(jìn)行bean的創(chuàng)建。

           /** 創(chuàng)建一個(gè)bean實(shí)例,為bean實(shí)例設(shè)置屬性值,調(diào)用post-processors-bean后置處理器 */@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {//...暫時(shí)忽略其他代碼  try {// 這里會(huì)首先觸發(fā)BeanPostProcessors ,如果這里能獲取到bean則直接返回,不再走doCreateBean    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);    if (bean != null) {      return bean;    }  }//...暫時(shí)忽略其他代碼
          //如果上面沒(méi)有獲取到bean,則會(huì)走doCreateBean--這也是創(chuàng)建bean的核心過(guò)程 Object beanInstance = doCreateBean(beanName, mbdToUse, args);//...暫時(shí)忽略其他代碼 return beanInstance;}

          在AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation中就會(huì)分別執(zhí)行bean后置處理器的前置和后置方法。

          protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {  Object bean = null;  if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {    // Make sure bean class is actually resolved at this point.    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {      Class targetType = determineTargetType(beanName, mbd);      if (targetType != null) {        bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);        if (bean != null) {          bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);        }      }    }    mbd.beforeInstantiationResolved = (bean != null);  }  return bean;}

          執(zhí)行后置處理器的前置方法如下所示:

          ③ doCreateBean

          AbstractAutowireCapableBeanFactory.doCreateBean是創(chuàng)建bean的核心方法,這會(huì)為bean屬性賦值并會(huì)觸發(fā)bean后置處理器、InitializingBean以及自定init方法等。

          protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)  throws BeanCreationException {
          // Instantiate the bean.--實(shí)例化beanBeanWrapper instanceWrapper = null;if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//獲取bean的包裝對(duì)象-這里很重要 instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);mbd.resolvedTargetType = beanType;
          // Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try {//調(diào)用MergedBeanDefinitionPostProcessors的postProcessMergedBeanDefinition方法 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; }}//...//這里暫時(shí)忽略其他代碼
          // Initialize the bean instance.--初始化bean實(shí)例Object exposedObject = bean;try {//如下方法很重要 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); }}//...
          // Register bean as disposable.try { registerDisposableBeanIfNecessary(beanName, bean, mbd);}//...return exposedObject;}

          ④ populateBean

          顧名思義,為bean實(shí)例屬性賦值。

          AbstractAutowireCapableBeanFactory.populateBean

          protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {//獲取屬性值列表PropertyValues pvs = mbd.getPropertyValues();
          //...該種符號(hào)表示暫時(shí)忽略其他代碼
          //在為bean屬性賦值前,給InstantiationAwareBeanPostProcessors 機(jī)會(huì)修改bean的狀態(tài)//應(yīng)用場(chǎng)景如支持字段注入boolean continueWithPropertyPopulation = true;
          //循環(huán)調(diào)用InstantiationAwareBeanPostProcessors 的postProcessAfterInstantiation方法if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } }}
          if (!continueWithPropertyPopulation) { return;}//解析autowire注解字段,進(jìn)行主動(dòng)注入if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
          // Add property values based on autowire by name if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); }
          // Add property values based on autowire by type if applicable. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); }
          pvs = newPvs;}
          boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
          //循環(huán)調(diào)用InstantiationAwareBeanPostProcessors 的postProcessPropertyValues方法if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); }}//在這里為屬性賦值,會(huì)進(jìn)行類(lèi)型轉(zhuǎn)換,這里注意關(guān)鍵詞deep copy//如果是引用類(lèi)型且bean沒(méi)有存在,則會(huì)進(jìn)行bean的創(chuàng)建過(guò)程applyPropertyValues(beanName, mbd, bw, pvs);}

          如下圖所示在創(chuàng)建sqlSessionFactoryBean過(guò)程中會(huì)創(chuàng)建其屬性globalConfiguration對(duì)象:

          如下圖所示在創(chuàng)建sqlSessionFactoryBean過(guò)程中(從左側(cè)的方法順序就可以看出來(lái))會(huì)創(chuàng)建其屬性PaginationInterceptor對(duì)象:

          如下圖所示在創(chuàng)建sqlSessionFactoryBean過(guò)程中(從左側(cè)的方法順序就可以看出來(lái))會(huì)創(chuàng)建其屬性SqlExplainInterceptor對(duì)象:

          如下圖所示在創(chuàng)建sqlSessionFactoryBean過(guò)程中(從左側(cè)的方法順序就可以看出來(lái))會(huì)創(chuàng)建其屬性PerformanceInterceptor對(duì)象:

          如下圖所示在創(chuàng)建sqlSessionFactoryBean過(guò)程中(從左側(cè)的方法順序就可以看出來(lái))會(huì)創(chuàng)建其屬性OptimisticLockerInterceptor對(duì)象:


          ⑤ initializeBean

          AbstractAutowireCapableBeanFactory.initializeBean源碼如下:

          protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {  if (System.getSecurityManager() != null) {    AccessController.doPrivileged(new PrivilegedAction<Object>() {      @Override      public Object run() {        invokeAwareMethods(beanName, bean);        return null;      }    }, getAccessControlContext());  }  else {  //調(diào)用意識(shí)/通知方法    invokeAwareMethods(beanName, bean);  }
          Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //調(diào)用bean后置處理器的前置方法 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //調(diào)用初始化方法 try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); }
          if (mbd == null || !mbd.isSynthetic()) { // //調(diào)用bean后置處理器的后置方法 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean;}

          AbstractAutowireCapableBeanFactory.invokeInitMethods方法源碼如下:

          protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)      throws Throwable {
          boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } //調(diào)用InitializingBean.afterPropertiesSet if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } }//調(diào)用自定義初始化方法 if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } }}

          如下圖所示,MybatisSqlSessionFactoryBean同樣實(shí)現(xiàn)了InitializingBean接口。那么我們就需要注意其afterPropertiesSet方法了。

          ⑥ MybatisSqlSessionFactoryBean.afterPropertiesSet

          如下所示,代碼很簡(jiǎn)短只是創(chuàng)建了sqlSessionFactory。

          @Overridepublic void afterPropertiesSet() throws Exception {    notNull(dataSource, "Property 'dataSource' is required"); //sqlSessionFactoryBuilder在populateBean的applyPropertyValues過(guò)程中已經(jīng)存在!    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();}

          進(jìn)入afterPropertiesSet()方法前MybatisSqlSessionFactoryBean如下所示:

          我們看一下sqlSessionFactory,這是一段很長(zhǎng)的過(guò)程:

          protected SqlSessionFactory buildSqlSessionFactory() throws Exception {    Configuration configuration;    // TODO 加載自定義 MybatisXmlConfigBuilder    MybatisXMLConfigBuilder xmlConfigBuilder = null;    if (this.configuration != null) {        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) { //通常如果配置了configLocation會(huì)從這里創(chuàng)建MybatisXMLConfigBuilder, //其構(gòu)造方法又創(chuàng)建了MybatisConfiguration        xmlConfigBuilder = new MybatisXMLConfigBuilder(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");        }        // TODO 使用自定義配置        configuration = new MybatisConfiguration();        if (this.configurationProperties != null) {            configuration.setVariables(this.configurationProperties);        }    }
          if (this.objectFactory != null) { configuration.setObjectFactory(this.objectFactory); }
          if (this.objectWrapperFactory != null) { configuration.setObjectWrapperFactory(this.objectWrapperFactory); }
          if (this.vfs != null) { configuration.setVfsImpl(this.vfs); }
          if (hasLength(this.typeAliasesPackage)) { // TODO 支持自定義通配符 String[] typeAliasPackageArray; if (typeAliasesPackage.contains("*") && !typeAliasesPackage.contains(",") && !typeAliasesPackage.contains(";")) { typeAliasPackageArray = PackageHelper.convertTypeAliasesPackage(typeAliasesPackage); } else { typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); } if (typeAliasPackageArray == null) { throw new MybatisPlusException("not find typeAliasesPackage:" + typeAliasesPackage); } for (String packageToScan : typeAliasPackageArray) { configuration.getTypeAliasRegistry().registerAliases(packageToScan, typeAliasesSuperType == null ? Object.class : typeAliasesSuperType); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases"); } } }
          // TODO 自定義枚舉類(lèi)掃描處理 if (hasLength(this.typeEnumsPackage)) { Set classes = null; if (typeEnumsPackage.contains("*") && !typeEnumsPackage.contains(",") && !typeEnumsPackage.contains(";")) { classes = PackageHelper.scanTypePackage(typeEnumsPackage); } else { String[] typeEnumsPackageArray = tokenizeToStringArray(this.typeEnumsPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); if (typeEnumsPackageArray == null) { throw new MybatisPlusException("not find typeEnumsPackage:" + typeEnumsPackage); } classes = new HashSet(); for (String typePackage : typeEnumsPackageArray) { classes.addAll(PackageHelper.scanTypePackage(typePackage)); } } // 取得類(lèi)型轉(zhuǎn)換注冊(cè)器 TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); for (Class cls : classes) { if (cls.isEnum()) { if (IEnum.class.isAssignableFrom(cls)) { typeHandlerRegistry.register(cls.getName(), com.baomidou.mybatisplus.handlers.EnumTypeHandler.class.getCanonicalName()); } else { // 使用原生 EnumOrdinalTypeHandler typeHandlerRegistry.register(cls.getName(), org.apache.ibatis.type.EnumOrdinalTypeHandler.class.getCanonicalName()); } } } }
          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 + "'"); } } }
          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)); // 設(shè)置元數(shù)據(jù)相關(guān) GlobalConfigUtils.setMetaData(dataSource, globalConfig); SqlSessionFactory sqlSessionFactory = this.sqlSessionFactoryBuilder.build(configuration); // TODO SqlRunner SqlRunner.FACTORY = sqlSessionFactory; // TODO 緩存 sqlSessionFactory globalConfig.setSqlSessionFactory(sqlSessionFactory); // TODO 設(shè)置全局參數(shù)屬性 globalConfig.signGlobalConfig(sqlSessionFactory); if (!isEmpty(this.mapperLocations)) { if (globalConfig.isRefresh()) { //TODO 設(shè)置自動(dòng)刷新配置 減少配置 new MybatisMapperRefresh(this.mapperLocations, sqlSessionFactory, 2, 2, true); } for (Resource mapperLocation : this.mapperLocations) { if (mapperLocation == null) { continue; }
          try { // TODO 這里也換了噢噢噢噢 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"); } } return sqlSessionFactory;}

          上面代碼主要做了如下事情:

          • 獲取MybatisXMLConfigBuilder對(duì)象

          • 獲取Configuration對(duì)象-MybatisConfiguration

          • 配置對(duì)象Configuration添加插件configuration.addInterceptor(plugin);

          • xmlConfigBuilder.parse()對(duì)configuration做進(jìn)一步處理

          • 獲取SpringManagedTransactionFactory用來(lái)創(chuàng)建SpringManagedTransaction

          • 獲取一個(gè)DefaultSqlSessionFactory實(shí)例對(duì)象

          • globalConfig.setSqlSessionFactory(sqlSessionFactory)中會(huì)創(chuàng)建MybatisSqlSessionTemplate

          • 解析mapperLocation對(duì)應(yīng)的一個(gè)個(gè)mapper配置文件,使用助手builderAssistant的addMappedStatement方法將一個(gè)個(gè)結(jié)點(diǎn)添加配置對(duì)象中

          • 其他屬性設(shè)置等等

          也就是說(shuō),在MybatisSqlSessionFactoryBean.afterPropertiesSet方法執(zhí)行結(jié)束后,SqlSessionFactory、SqlSessionTemplate、Configuration等都已存在!

          【3】查詢(xún)執(zhí)行流程分析

          示例代碼如下:

          List?emps?=?employeeMapper.selectPage(page,?null);

          如下圖所示,此時(shí)我們獲取到的employeeMapper其實(shí)是個(gè)代理對(duì)象:


          版權(quán)聲明:本文為博主原創(chuàng)文章,遵循?CC 4.0 BY-SA?版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。

          本文鏈接:

          https://janus.blog.csdn.net/article/details/108441600





          粉絲福利:108本java從入門(mén)到大神精選電子書(shū)領(lǐng)取

          ???

          ?長(zhǎng)按上方鋒哥微信二維碼?2 秒
          備注「1234」即可獲取資料以及
          可以進(jìn)入java1234官方微信群



          感謝點(diǎn)贊支持下哈?

          瀏覽 86
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色色午夜 | 操香蕉| 大香久久| 国产乱婬AAAA片视频软件 | 日韩美女射|