spring 整合mybatis源码分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

spring 整合mybatis时,底层就是依靠两个类,sqlSessionFactoryBean 和 mapperFactoryBean 实现;这两个类有一个共同的特点的特点,就是都实现了spring的FactoryBean InitializingBean 接口;实现了FactoryBean 接口,当调用getBean时返回的对象为getObject()方法返回的对象 ;而实现InitializingBean时,会在bean初始化时调用afterPropetiesSet 方法进行bean属性的封装,通常就是读取applicationContext.xml的配置信息;

1:sqlSessionFactoryBean 分析<!– 配置sqlsessionFactory –>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
       <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"></property>
       <property name="mapperLocations" value="classpath:mapping/*.map.xml"></property>
       <property name="dataSource" ref="dataSource"></property>
    </bean>

a:看看afterPropertiesSet接口实现;

    public void afterPropertiesSet() throws Exception {
            Assert.notNull(this.dataSource, "Property 'dataSource' is required");
            Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
            this.sqlSessionFactory = this.buildSqlSessionFactory();
        }

        protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
            XMLConfigBuilder xmlConfigBuilder = null;
            Configuration configuration;
            if (this.configLocation != null) {
                xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
                configuration = xmlConfigBuilder.getConfiguration();
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
                }

                configuration = new Configuration();
                configuration.setVariables(this.configurationProperties);
            }

            if (this.objectFactory != null) {
                configuration.setObjectFactory(this.objectFactory);
            }

            if (this.objectWrapperFactory != null) {
                configuration.setObjectWrapperFactory(this.objectWrapperFactory);
            }

            String[] typeHandlersPackageArray;
            String[] arr$;
            int len$;
            int i$;
            String packageToScan;
            if (StringUtils.hasLength(this.typeAliasesPackage)) {
                typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeAliasesPackage, ",; \t\n");
                arr$ = typeHandlersPackageArray;
                len$ = typeHandlersPackageArray.length;

                for(i$ = 0; i$ < len$; ++i$) {
                    packageToScan = arr$[i$];
                    configuration.getTypeAliasRegistry().registerAliases(packageToScan, this.typeAliasesSuperType == null ? Object.class : this.typeAliasesSuperType);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Scanned package: '" + packageToScan + "' for aliases");
                    }
                }
            }

            int len$;
            if (!ObjectUtils.isEmpty(this.typeAliases)) {
                Class[] arr$ = this.typeAliases;
                len$ = arr$.length;

                for(len$ = 0; len$ < len$; ++len$) {
                    Class<?> typeAlias = arr$[len$];
                    configuration.getTypeAliasRegistry().registerAlias(typeAlias);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Registered type alias: '" + typeAlias + "'");
                    }
                }
            }

            if (!ObjectUtils.isEmpty(this.plugins)) {
                Interceptor[] arr$ = this.plugins;
                len$ = arr$.length;

                for(len$ = 0; len$ < len$; ++len$) {
                    Interceptor plugin = arr$[len$];
                    configuration.addInterceptor(plugin);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Registered plugin: '" + plugin + "'");
                    }
                }
            }

            if (StringUtils.hasLength(this.typeHandlersPackage)) {
                typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeHandlersPackage, ",; \t\n");
                arr$ = typeHandlersPackageArray;
                len$ = typeHandlersPackageArray.length;

                for(i$ = 0; i$ < len$; ++i$) {
                    packageToScan = arr$[i$];
                    configuration.getTypeHandlerRegistry().register(packageToScan);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Scanned package: '" + packageToScan + "' for type handlers");
                    }
                }
            }

            if (!ObjectUtils.isEmpty(this.typeHandlers)) {
                TypeHandler[] arr$ = this.typeHandlers;
                len$ = arr$.length;

                for(len$ = 0; len$ < len$; ++len$) {
                    TypeHandler<?> typeHandler = arr$[len$];
                    configuration.getTypeHandlerRegistry().register(typeHandler);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Registered type handler: '" + typeHandler + "'");
                    }
                }
            }

            if (xmlConfigBuilder != null) {
                try {
                    xmlConfigBuilder.parse();
                    if (logger.isDebugEnabled()) {
                        logger.debug("Parsed configuration file: '" + this.configLocation + "'");
                    }
                } catch (Exception var23) {
                    throw new NestedIOException("Failed to parse config resource: " + this.configLocation, var23);
                } finally {
                    ErrorContext.instance().reset();
                }
            }

            if (this.transactionFactory == null) {
                this.transactionFactory = new SpringManagedTransactionFactory();
            }

            Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
            configuration.setEnvironment(environment);
            if (this.databaseIdProvider != null) {
                try {
                    configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
                } catch (SQLException var22) {
                    throw new NestedIOException("Failed getting a databaseId", var22);
                }
            }

            if (!ObjectUtils.isEmpty(this.mapperLocations)) {
                Resource[] arr$ = this.mapperLocations;
                len$ = arr$.length;

                for(i$ = 0; i$ < len$; ++i$) {
                    Resource mapperLocation = arr$[i$];
                    if (mapperLocation != null) {
                        try {
                            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), configuration, mapperLocation.toString(), configuration.getSqlFragments());
                            xmlMapperBuilder.parse();
                        } catch (Exception var20) {
                            throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", var20);
                        } 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 this.sqlSessionFactoryBuilder.build(configuration);
        }

可以看出,函数方法的主要目的就是对sqlSessionFactry的初始化;

b:getObject方法:返回sqlSessionFactory对象

     public SqlSessionFactory getObject() throws Exception {
            if (this.sqlSessionFactory == null) {
                this.afterPropertiesSet();
            }

            return this.sqlSessionFactory;
        }

2:mapperFactoryBean 解析

原始用法:

    <bean class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="search.dao.userDao"></property>
            <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
    </bean>
    @Override
        public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
            // Let abstract subclasses check their configuration.
            checkDaoConfig();

            // Let concrete implementations initialize themselves.
            try {
                initDao();
            }
            catch (Exception ex) {
                throw new BeanInitializationException("Initialization of DAO failed", ex);
            }
        }

    protected void checkDaoConfig() {
            super.checkDaoConfig();
            Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
            Configuration configuration = this.getSqlSession().getConfiguration();
            if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
                try {
                    configuration.addMapper(this.mapperInterface);
                } catch (Throwable var6) {
                    this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);
                    throw new IllegalArgumentException(var6);
                } finally {
                    ErrorContext.instance().reset();
                }
            }

        }

    protected void checkDaoConfig() {
            super.checkDaoConfig();
            Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
            Configuration configuration = this.getSqlSession().getConfiguration();
            if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
                try {
                    configuration.addMapper(this.mapperInterface);
                } catch (Throwable var6) {
                    this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);
                    throw new IllegalArgumentException(var6);
                } finally {
                    ErrorContext.instance().reset();
                }
            }

        }

mapperFactoryBean间接实现了InitializingBean接口,而主要作用是在checkDaoConfig方法中将接口注入到映射类型中;这里对接口方法进行了解析注册;

2:getObject方法

    public T getObject() throws Exception {
            return this.getSqlSession().getMapper(this.mapperInterface);
        }

这段代码是mybatis单独的代码逻辑,是实现dao代理的入口;返回的对象为接口代理对象;

3 MapperScannerConfigurer解析

MapperScannerConfigurer是为了提高创建映射器的效率,而自动实现通过扫描特定包,自动帮我们成批量创建映射器。

    <!-- 配置扫描包,加载mapper代理对象 -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="search.dao"></property>
        </bean>

20191102100639\_1.png

虽然MapperScannerConfigurer 也实现了InitializingBean接口,但是实现方法AfterPropertiesSet并没有实现任何逻辑。同时虽然也间接实现了BeanFactoryPoscessor,这个类与后处理器BeanPostPrecessor功能类似,会在初始化前后调用相应接口方法;但是postProcessBeanFactory方法,并没有实现任务逻辑;最后在实现的接口类,BeanDefinitionRegistryPostProcessor中实现方法postProcessBeanDefinitionRegistry找到了业务处理逻辑。

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            if (this.processPropertyPlaceHolders) {
                this.processPropertyPlaceHolders();
            }

            ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
            scanner.setAddToConfig(this.addToConfig);
            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);
            scanner.registerFilters();
            scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
        }

在scan方法调用的doScan方法中可以清晰的看出,MapperScannerConfigurer类是把扫描的dao接口,通过编码的方式动态注册一个类型为MapperFactoryBean的bean,将接口名存入其属性字段中;最终调用接口时,还是通过getObject方法返回sqlSession.getMapper(interfaceName);

    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
            Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
            if (beanDefinitions.isEmpty()) {
                this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
            } else {
                Iterator i$ = beanDefinitions.iterator();

                while(i$.hasNext()) {
                    BeanDefinitionHolder holder = (BeanDefinitionHolder)i$.next();
                    GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition();
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface");
                    }
                    //在这里开始构造MapperFactoryBean对象类型的bean,把接口属性存入
                    //MapperFactoryBean中
                    definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
                    definition.setBeanClass(MapperFactoryBean.class);
                    definition.getPropertyValues().add("addToConfig", this.addToConfig);
                    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;
                    }

                    if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
                        if (explicitFactoryUsed) {
                            this.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) {
                            this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
                        }

                        definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
                        explicitFactoryUsed = true;
                    }

                    if (!explicitFactoryUsed) {
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
                        }

                        definition.setAutowireMode(2);
                    }
                }
            }

            return beanDefinitions;
        }

来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring 整合mybatis源码分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏