1. SqlMapClientFactoryBean:
Spring中通过SqlMapClientTemplate提供对Ibatis的支持,与Spring对Hibernate的支持类似,Spring中SqlMapClientFactoryBean就是管理Ibatis的IoC容器,我们首先分析SqlMapClientFactoryBean的源码:
- //Spring管理Ibatis的IoC容器
- publicclassSqlMapClientFactoryBeanimplementsFactoryBean<SqlMapClient>,InitializingBean{
- //当前线程绑定Ibatisblob/clob等大字段数据处理器资源
- privatestaticfinalThreadLocal<LobHandler>configTimeLobHandlerHolder=newThreadLocal<LobHandler>();
- publicstaticLobHandlergetConfigTimeLobHandler(){
- returnconfigTimeLobHandlerHolder.get();
- }
- //Ibatis配置文件路径
- privateResource[]configLocations;
- //Ibatis映射文件路径
- privateResource[]mappingLocations;
- //IbatissqlMapClient属性
- privatePropertiessqlMapClientProperties;
- //数据源
- privateDataSourcedataSource;
- //使用Spring事务包装数据源
- privatebooleanuseTransactionAwareDataSource=true;
- //事务配置类
- privateClasstransactionConfigClass=ExternalTransactionConfig.class;
- //事务配置属性
- privatePropertiestransactionConfigProperties;
- //blob/clob等lob类型处理器
- privateLobHandlerlobHandler;
- //IbatissqlMapClient
- privateSqlMapClientsqlMapClient;
- publicSqlMapClientFactoryBean(){
- this.transactionConfigProperties=newProperties();
- //不允许事务自动提交
- this.transactionConfigProperties.setProperty("SetAutoCommitAllowed","false");
- }
- //指定IbatissqlMapClient配置文件路径
- publicvoidsetConfigLocation(ResourceconfigLocation){
- this.configLocations=(configLocation!=null?newResource[]{configLocation}:null);
- }
- //指定多个sqlMapClient配置文件路径,这些配置文件在运行时合并
- publicvoidsetConfigLocations(Resource[]configLocations){
- this.configLocations=configLocations;
- }
- //指定Ibatis映射文件路径,这些映射文件在运行时被合并到SqlMapClient的配置中
- publicvoidsetMappingLocations(Resource[]mappingLocations){
- this.mappingLocations=mappingLocations;
- }
- //指定IbatisSqlMapClient可选的属性,即在SqlMapClient配置文件中通过属性
- //文件设置的属性
- publicvoidsetSqlMapClientProperties(PropertiessqlMapClientProperties){
- this.sqlMapClientProperties=sqlMapClientProperties;
- }
- //设置Ibatis使用的数据源
- publicvoidsetDataSource(DataSourcedataSource){
- this.dataSource=dataSource;
- }
- //设置数据源是否使用事务包装
- publicvoidsetUseTransactionAwareDataSource(booleanuseTransactionAwareDataSource){
- this.useTransactionAwareDataSource=useTransactionAwareDataSource;
- }
- //设置Ibatis使用的事务配置类,默认是//com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
- publicvoidsetTransactionConfigClass(ClasstransactionConfigClass){
- if(transactionConfigClass==null||!TransactionConfig.class.isAssignableFrom(transactionConfigClass)){
- thrownewIllegalArgumentException("InvalidtransactionConfigClass:doesnotimplement"+
- "com.ibatis.sqlmap.engine.transaction.TransactionConfig");
- }
- this.transactionConfigClass=transactionConfigClass;
- }
- //设置Ibatis事务配置类属性
- publicvoidsetTransactionConfigProperties(PropertiestransactionConfigProperties){
- this.transactionConfigProperties=transactionConfigProperties;
- }
- //设置Ibatis使用的处理clob/blob等大字段的处理器
- publicvoidsetLobHandler(LobHandlerlobHandler){
- this.lobHandler=lobHandler;
- }
- //IoC容器初始化完成之后的回调方法,是InitializingBean接口的实现方法
- publicvoidafterPropertiesSet()throwsException{
- //配置lob处理器
- if(this.lobHandler!=null){
- configTimeLobHandlerHolder.set(this.lobHandler);
- }
- //创建Ibatis的SqlMapClient
- try{
- this.sqlMapClient=buildSqlMapClient(this.configLocations,this.mappingLocations,this.sqlMapClientProperties);
- //为创建的SqlMapClient设置数据源
- if(this.dataSource!=null){
- //创建事务配置实例
- TransactionConfigtransactionConfig=(TransactionConfig)this.transactionConfigClass.newInstance();
- //获取数据源
- DataSourcedataSourceToUse=this.dataSource;
- //如果Ibatis配置指定使用事务包装的数据源,并且当前获取到的数据源
- //不是事务包装数据源代理类型
- if(this.useTransactionAwareDataSource&&!(this.dataSourceinstanceofTransactionAwareDataSourceProxy)){
- //为指定数据源创建事务包装代理
- dataSourceToUse=newTransactionAwareDataSourceProxy(this.dataSource);
- }
- //事务配置对象设置数据源
- transactionConfig.setDataSource(dataSourceToUse);
- //初始化事务配置对象transactionConfig.initialize(this.transactionConfigProperties);
- applyTransactionConfig(this.sqlMapClient,transactionConfig);
- }
- }
- //创建SqlMapClient成功后,清除当前线程绑定的Lob处理器资源
- finally{
- if(this.lobHandler!=null){
- configTimeLobHandlerHolder.remove();
- }
- }
- }
- //具体创建SqlMapClient的方法,根据给定的Ibatis配置文件、Ibatis映射文件
- //和Ibatis配置中的属性文件创建SqlMapClient
- protectedSqlMapClientbuildSqlMapClient(
- Resource[]configLocations,Resource[]mappingLocations,Propertiesproperties)
- throwsIOException{
- //如果给定Ibatis配置文件路径为空
- if(ObjectUtils.isEmpty(configLocations)){
- thrownewIllegalArgumentException("Atleast1'configLocation'entryisrequired");
- }
- SqlMapClientclient=null;
- //创建Ibatis配置文件解析器
- SqlMapConfigParserconfigParser=newSqlMapConfigParser();
- //遍历所有的Ibatis配置文件
- for(ResourceconfigLocation:configLocations){
- //获取Ibatis配置文件输入流
- InputStreamis=configLocation.getInputStream();
- try{
- //创建IbatisSqlMapClient
- client=configParser.parse(is,properties);
- }
- catch(RuntimeExceptionex){
- thrownewNestedIOException("Failedtoparseconfigresource:"+configLocation,ex.getCause());
- }
- }
- //如果Ibatis映射文件不为null
- if(mappingLocations!=null){
- //根据Ibatis配置文件解析器创建Ibatis映射文件解析器
- SqlMapParsermapParser=SqlMapParserFactory.createSqlMapParser(configParser);
- //遍历所给定的Ibatis映射文件
- for(ResourcemappingLocation:mappingLocations){
- try{
- //解析Ibatis映射文件
- mapParser.parse(mappingLocation.getInputStream());
- }
- catch(NodeletExceptionex){
- thrownewNestedIOException("Failedtoparsemappingresource:"+mappingLocation,ex);
- }
- }
- }
- //返回创建的SqlMapClient对象
- returnclient;
- }
- //将Ibatis配置中指定的事务配置应用到SqlMapClient上
- protectedvoidapplyTransactionConfig(SqlMapClientsqlMapClient,TransactionConfigtransactionConfig){
- //如果SqlMapClient不是ExtendedSqlMapClient类型,则无法将Ibatis配置//中指定的事务配置应用到SqlMapClient对象
- if(!(sqlMapClientinstanceofExtendedSqlMapClient)){
- thrownewIllegalArgumentException(
- "CannotsetTransactionConfigwithDataSourceforSqlMapClientifnotoftype"+
- "ExtendedSqlMapClient:"+sqlMapClient);
- }
- ExtendedSqlMapClientextendedClient=(ExtendedSqlMapClient)sqlMapClient;
- //设置最大并发Ibatis事务数量transactionConfig.setMaximumConcurrentTransactions(extendedClient.getDelegate().getMaxTransactions());
- //为SqlMapClient设置事务处理器
- extendedClient.getDelegate().setTxManager(newTransactionManager(transactionConfig));
- }
- //SpringIoC容器中对应用提供的一个获取被管理对象的方法,应该通过此方法获
- //取被SpringIoC容器管理的IbatisSqlMapClient对象
- publicSqlMapClientgetObject(){
- returnthis.sqlMapClient;
- }
- //获取SqlMapClient的类型
- publicClass<?extendsSqlMapClient>getObjectType(){
- return(this.sqlMapClient!=null?this.sqlMapClient.getClass():SqlMapClient.class);
- }
- //默认SpringIoC容器中管理的对象是单态模式的
- publicbooleanisSingleton(){
- returntrue;
- }
- //Ibatis映射解析器工厂,内部类
- privatestaticclassSqlMapParserFactory{
- //创建Ibatis映射解析器
- publicstaticSqlMapParsercreateSqlMapParser(SqlMapConfigParserconfigParser){
- XmlParserStatestate=null;
- try{
- //使用JDK反射机制获取SqlMapConfigParser类中的state字段
- FieldstateField=SqlMapConfigParser.class.getDeclaredField("state");
- //使用JDK反射机制使state字段可以被访问,主要解决private、//protect和默认访问权限没有提供get方法的情况
- stateField.setAccessible(true);
- //使用Ibatis配置解析器获取指定字段的值
- state=(XmlParserState)stateField.get(configParser);
- }
- catch(Exceptionex){
- thrownewIllegalStateException("iBATIS2.3.2'state'fieldnotfoundinSqlMapConfigParserclass-"+
- "pleaseupgradetoIBATIS2.3.2orhigherinordertousethenew'mappingLocations'feature."+ex);
- }
- //为指定字段值创建Ibatis映射解析器
- returnnewSqlMapParser(state);
- }
- }
- }
SqlMapClientFactoryBean实现了Spring的FactoryBean接口,是Spring中管理Ibatis的IoC容器,在IoC容器初始化过程中主要完成定位Ibatis配置文件和Ibatis映射文件等工作。同时SqlMapClientFactoryBean实现了InitializingBean接口,实现了afterPropertiesSet方法,该方法是在IoC容器初始化完成之后由IoC容器进行回调的,在该方法中主要是根据定义的Ibatis配置和映射文件创建Ibatis的SqlMapClient对象的过程。
2.SqlMapClientTemplate:
Spring通过SqlMapClientTemplate对Ibatis一些通用操作做统一的封装处理,同时也对Ibatis的API做了一些封装,方便开发者使用,下面我们继续分析SqlMapClientTemplate对Ibatis封装的实现。
(1).execute方法的实现:
同JdbcTemplate和HibernateTemplate一样,Spring在SqlMapClientTemplate中也是通过execute方法封装Ibatis增删改查前的通用操作,同时在execute方法中调用相应的回调对象的回调方法来真正完成Ibatis的处理操作,execute方法源码如下:
- public<T>Texecute(SqlMapClientCallback<T>action)throwsDataAccessException{
- Assert.notNull(action,"Callbackobjectmustnotbenull");
- Assert.notNull(this.sqlMapClient,"NoSqlMapClientspecified");
- //通过SqlMapClient对象打开一个IbatisSqlMapSession
- SqlMapSessionsession=this.sqlMapClient.openSession();
- if(logger.isDebugEnabled()){
- logger.debug("OpenedSqlMapSession["+session+"]foriBATISoperation");
- }
- ConnectionibatisCon=null;
- try{
- ConnectionspringCon=null;
- //获取数据源
- DataSourcedataSource=getDataSource();
- //根据数据源是否是事务包装数据源代理类型,判断数据源是否需要事务包装
- booleantransactionAware=(dataSourceinstanceofTransactionAwareDataSourceProxy);
- try{
- //获取连接
- ibatisCon=session.getCurrentConnection();
- //如果当前IbatisSqlMapSession还没有创建过连接
- if(ibatisCon==null){
- //如果Ibatis数据源已经在Spring事务管理之下,则直接使用数据源//创建连接,否则,使用DataSourceUtils创建连接,并且创建的连//接置于Spring事务管理之中
- springCon=(transactionAware?
- dataSource.getConnection():DataSourceUtils.doGetConnection(dataSource));
- session.setUserConnection(springCon);
- if(logger.isDebugEnabled()){
- logger.debug("ObtainedJDBCConnection["+springCon+"]foriBATISoperation");
- }
- }
- //如果当前IbatisSqlMapSession已经创建过连接,则直接使用
- else{
- if(logger.isDebugEnabled()){
- logger.debug("ReusingJDBCConnection["+ibatisCon+"]foriBATISoperation");
- }
- }
- }
- catch(SQLExceptionex){
- thrownewCannotGetJdbcConnectionException("CouldnotgetJDBCConnection",ex);
- }
- //调用具体增删改查操作回调对象的方法
- try{
- returnaction.doInSqlMapClient(session);
- }
- catch(SQLExceptionex){
- throwgetExceptionTranslator().translate("SqlMapClientoperation",null,ex);
- }
- finally{
- try{
- //释放连接
- if(springCon!=null){
- if(transactionAware){
- springCon.close();
- }
- else{
- DataSourceUtils.doReleaseConnection(springCon,dataSource);
- }
- }
- }
- catch(Throwableex){
- logger.debug("CouldnotcloseJDBCConnection",ex);
- }
- }
- }
- //关闭Ibatis的SqlMapSession
- finally{
- if(ibatisCon==null){
- session.close();
- }
- }
- }
(2).Spring封装Ibatis API的方法:
我们以Spring的queryForObject方法为例,分析Spring封装Ibatis API的实现,源码如下:
- //查询对象
- publicObjectqueryForObject(finalStringstatementName,finalObjectparameterObject)
- throwsDataAccessException{
- //调用execute方法,参数是实现了SqlMapClientCallback接口的匿名内部类,
- //execute方法中回调该对象的doInSqlMapClient方法
- returnexecute(newSqlMapClientCallback<Object>(){
- //真正调用IbatisAPI做具体操作处理的方法
- publicObjectdoInSqlMapClient(SqlMapExecutorexecutor)throwsSQLException{
- //调用IbatisSqlMapSession对象的queryForObejct方法
- returnexecutor.queryForObject(statementName,parameterObject);
- }
- });
- }