使用过SSM的框架的都知道mybatis这个持久层框架,今天小编就来简单说说这个框架的核心工厂类sqlSessionFactory的加载过程,一般的SSM框架我们都会在spring的application.xml中引入如下的配置:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="configLocation" value="classpath:config/mybatis-config.xml"></property> </bean>
其中的SqlSessionFactoryBean便是加载sqlSessionFactory的入口,首先我们来看看这个类的源代码:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> { private static final Log logger = LogFactory.getLog(SqlSessionFactoryBean.class); private Resource configLocation; private Resource[] mapperLocations; private DataSource dataSource; private TransactionFactory transactionFactory; private Properties configurationProperties; private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); private SqlSessionFactory sqlSessionFactory;
其中标红的两处,就是我们在application.xml中注入的两个属性,从源码中我们可以看出该类实现了InitializingBean接口,实现了其afterPropertiesSet()方法,
该方法是在当前bean的所有属性被初始化完成之后再执行,也就是其中的datasource和configurationProperties等属性,接下来我们看看这个方法主要干什么了?
1 public void afterPropertiesSet() throws Exception { 2 notNull(dataSource, "Property 'dataSource' is required"); 3 notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required"); 4 5 this.sqlSessionFactory = buildSqlSessionFactory(); 6 }
其中第5行很明显的buildSqlSessionFactory()方法初始化了sqlSessionFactory ,接下来我们看看这个方法的主要行为:
1 Configuration configuration; 2 3 XMLConfigBuilder xmlConfigBuilder = null; 4 if (this.configLocation != null) { 5 xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties); 6 configuration = xmlConfigBuilder.getConfiguration(); 7 } else { 8 if (logger.isDebugEnabled()) { 9 logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration"); 10 } 11 configuration = new Configuration(); 12 configuration.setVariables(this.configurationProperties); 13 } 14 15 if (this.objectFactory != null) { 16 configuration.setObjectFactory(this.objectFactory); 17 } 18 19 if (this.objectWrapperFactory != null) { 20 configuration.setObjectWrapperFactory(this.objectWrapperFactory); 21 } 22 23 if (hasLength(this.typeAliasesPackage)) { 24 String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage, 25 ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); 26 for (String packageToScan : typeAliasPackageArray) { 27 configuration.getTypeAliasRegistry().registerAliases(packageToScan, 28 typeAliasesSuperType == null ? Object.class : typeAliasesSuperType); 29 if (logger.isDebugEnabled()) { 30 logger.debug("Scanned package: '" + packageToScan + "' for aliases"); 31 } 32 } 33 } 34 35 if (!isEmpty(this.typeAliases)) { 36 for (Class<?> typeAlias : this.typeAliases) { 37 configuration.getTypeAliasRegistry().registerAlias(typeAlias); 38 if (logger.isDebugEnabled()) { 39 logger.debug("Registered type alias: '" + typeAlias + "'"); 40 } 41 } 42 } 43 44 if (!isEmpty(this.plugins)) { 45 for (Interceptor plugin : this.plugins) { 46 configuration.addInterceptor(plugin); 47 if (logger.isDebugEnabled()) { 48 logger.debug("Registered plugin: '" + plugin + "'"); 49 } 50 } 51 } 52 53 if (hasLength(this.typeHandlersPackage)) { 54 String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage, 55 ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); 56 for (String packageToScan : typeHandlersPackageArray) { 57 configuration.getTypeHandlerRegistry().register(packageToScan); 58 if (logger.isDebugEnabled()) { 59 logger.debug("Scanned package: '" + packageToScan + "' for type handlers"); 60 } 61 } 62 } 63 64 if (!isEmpty(this.typeHandlers)) { 65 for (TypeHandler<?> typeHandler : this.typeHandlers) { 66 configuration.getTypeHandlerRegistry().register(typeHandler); 67 if (logger.isDebugEnabled()) { 68 logger.debug("Registered type handler: '" + typeHandler + "'"); 69 } 70 } 71 } 72 73 if (xmlConfigBuilder != null) { 74 try { 75 xmlConfigBuilder.parse(); 76 77 if (logger.isDebugEnabled()) { 78 logger.debug("Parsed configuration file: '" + this.configLocation + "'"); 79 } 80 } catch (Exception ex) { 81 throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex); 82 } finally { 83 ErrorContext.instance().reset(); 84 } 85 } 86 87 if (this.transactionFactory == null) { 88 this.transactionFactory = new SpringManagedTransactionFactory(); 89 } 90 91 Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource); 92 configuration.setEnvironment(environment); 93 94 if (this.databaseIdProvider != null) { 95 try { 96 configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource)); 97 } catch (SQLException e) { 98 throw new NestedIOException("Failed getting a databaseId", e); 99 } 100 } 101 102 if (!isEmpty(this.mapperLocations)) { 103 for (Resource mapperLocation : this.mapperLocations) { 104 if (mapperLocation == null) { 105 continue; 106 } 107 108 try { 109 XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), 110 configuration, mapperLocation.toString(), configuration.getSqlFragments()); 111 xmlMapperBuilder.parse(); 112 } catch (Exception e) { 113 throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e); 114 } finally { 115 ErrorContext.instance().reset(); 116 } 117 118 if (logger.isDebugEnabled()) { 119 logger.debug("Parsed mapper file: '" + mapperLocation + "'"); 120 } 121 } 122 } else { 123 if (logger.isDebugEnabled()) { 124 logger.debug("Property 'mapperLocations' was not specified or no matching resources found"); 125 } 126 }
该方法主要就是设置configuration参数,首先是从mybatis-config.xml中获取对应的配置信息,然后再从spring的注入属性中获取所有的配置信息,从后调用
sqlSessionFactoryBuilder.build(configuration)方法获取sqlSessionFactory的实例。
由于整个加载过程没有过多的难点,所以就介绍到这里,感兴趣的朋友可以自己去源码,了解更多知识。