在Spring中集成iBATIS是一件很简单的事情,只需要简单的配置即可;在Spring中使用iBATIS的配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd "> <context:component-scan base-package="com.david.*" /> <aop:aspectj-autoproxy /> <context:property-placeholder location="classpath:META-INF/config.properties" /> <!-- 定义数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.ams.driver}" /> <property name="jdbcUrl" value="${jdbc.ams.url}" /> <property name="user" value="${jdbc.ams.username}" /> <property name="password" value="${jdbc.ams.password}" /> <property name="initialPoolSize" value="${initialSize}" /> <property name="minPoolSize" value="${minPoolSize}" /> <property name="maxPoolSize" value="${maxActive}" /> <property name="acquireIncrement" value="${acquireIncrement}" /> <property name="maxIdleTime" value="${maxIdleTime}" /> </bean> <!-- 定义jdbc模板类 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:META-INF/sqlmap/sqlmap.xml" /> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
我们知道SqlMapClientImpl实例是iBTATIS的门面,所有的操作都是调用client的方法,那么SqlMapClient的实例又是如何,在什么地方被创建的呢?
我们通过配置文件可以发现,client是通过一个工厂方法创建的,具体的流程如下图所示:
通过SqlMapClientFactoryBean源码可以发现,该类实现了InitializingBean
public class SqlMapClientFactoryBean implements FactoryBean<SqlMapClient>, InitializingBean {
这个接口的作用又是什么呢?可以看看该接口的注释:
/** * Invoked by a BeanFactory after it has set all bean properties supplied * (and satisfied BeanFactoryAware and ApplicationContextAware). * <p>This method allows the bean instance to perform initialization only * possible when all bean properties have been set and to throw an * exception in the event of misconfiguration. * @throws Exception in the event of misconfiguration (such * as failure to set an essential property) or if initialization fails. */ void afterPropertiesSet() throws Exception;
一个类实现了这个接口就会在所有属性初始化完成后,调用afterPropertiesSet()方法,而SqlMapClientFactoryBean正是在这个方法中进行SqlMapClientImpl的实例初始化。
public void afterPropertiesSet() throws Exception { if (this.lobHandler != null) { // Make given LobHandler available for SqlMapClient configuration. // Do early because because mapping resource might refer to custom types. configTimeLobHandlerHolder.set(this.lobHandler); } try { this.sqlMapClient = buildSqlMapClient(this.configLocations, this.mappingLocations, this.sqlMapClientProperties); // Tell the SqlMapClient to use the given DataSource, if any. if (this.dataSource != null) { TransactionConfig transactionConfig = (TransactionConfig) this.transactionConfigClass.newInstance(); DataSource dataSourceToUse = this.dataSource; if (this.useTransactionAwareDataSource && !(this.dataSource instanceof TransactionAwareDataSourceProxy)) { dataSourceToUse = new TransactionAwareDataSourceProxy(this.dataSource); } transactionConfig.setDataSource(dataSourceToUse); transactionConfig.initialize(this.transactionConfigProperties); applyTransactionConfig(this.sqlMapClient, transactionConfig); } } finally { if (this.lobHandler != null) { // Reset LobHandler holder. configTimeLobHandlerHolder.remove(); } } } /** * Build a SqlMapClient instance based on the given standard configuration. * <p>The default implementation uses the standard iBATIS {@link SqlMapClientBuilder} * API to build a SqlMapClient instance based on an InputStream (if possible, * on iBATIS 2.3 and higher) or on a Reader (on iBATIS up to version 2.2). * @param configLocations the config files to load from * @param properties the SqlMapClient properties (if any) * @return the SqlMapClient instance (never <code>null</code>) * @throws IOException if loading the config file failed * @see com.ibatis.sqlmap.client.SqlMapClientBuilder#buildSqlMapClient */ protected SqlMapClient buildSqlMapClient( Resource[] configLocations, Resource[] mappingLocations, Properties properties) throws IOException { if (ObjectUtils.isEmpty(configLocations)) { throw new IllegalArgumentException("At least 1 'configLocation' entry is required"); } SqlMapClient client = null; SqlMapConfigParser configParser = new SqlMapConfigParser(); for (Resource configLocation : configLocations) { InputStream is = configLocation.getInputStream(); try { client = configParser.parse(is, properties); } catch (RuntimeException ex) { throw new NestedIOException("Failed to parse config resource: " + configLocation, ex.getCause()); } } if (mappingLocations != null) { SqlMapParser mapParser = SqlMapParserFactory.createSqlMapParser(configParser); for (Resource mappingLocation : mappingLocations) { try { mapParser.parse(mappingLocation.getInputStream()); } catch (NodeletException ex) { throw new NestedIOException("Failed to parse mapping resource: " + mappingLocation, ex); } } } return client; }
跟踪代码就可以发现其后的初始化就是一层层new 一个新的对象。