spring 整合mybatis源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Java_Jsp_Ssh/article/details/82598180

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>

 虽然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;
    }

猜你喜欢

转载自blog.csdn.net/Java_Jsp_Ssh/article/details/82598180
今日推荐