在不整合spring的情况下,通过mybatis的xml配置文件配置mybatis的各种属性,完成SqlSessionFactory初始化。
public SqlSessionFactory getSqlSessionFactory() throws IOException {
return new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//通过XMLConfigBuilder对象 解析 xml配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
//父类的configuration属性赋值为new Configuration() , configuration对象很重要 , 里面保存非常多的属性。
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
//configuration的的variables设置为props
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
//parser赋值为parser
this.parser = parser;
}
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//从根标签configuration开始解析
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
//解析properties标签 比如<properties resource="database.properties"/> 引入配置信息
//使得可以在xml配置文件中使用${}占位符获取相应的值
propertiesElement(root.evalNode("properties"));
//解析settings标签 获取子标签setting的name value属性,封装为Properties对象返回
//<setting name="safeResultHandlerEnabled" value="true"/> 开启自动驼峰转换
//<setting name="cacheEnabled" value="true"/> 开启二级缓存功能 (一般不去使用,特别是分布式的环境)
Properties settings = settingsAsProperties(root.evalNode("settings"));
//获取vfsImpl属性值,设置到configuration的vfsImpl属性中
//且再VFS类的USER_IMPLEMENTATIONS容器中放入该vfsImpl对应的class对象
//一般使用默认的DefaultVFS
loadCustomVfs(settings);
//获取到logImpl的属性值,设置到configuration的logImpl属性中
//且把实例化该属性值对应的类的构造函数,把该日志构造函数设置到LogFactory的logConstructor属性中
loadCustomLogImpl(settings);
//解析typeAliases标签
typeAliasesElement(root.evalNode("typeAliases"));
//解析plugins标签
pluginElement(root.evalNode("plugins"));
//这几个属性一般使用默认的就行,数据库字段映射到实体类用到的类
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
//将setting标签配置的各种属性封装到configuration对应的属性中
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
//解析environments标签
environmentsElement(root.evalNode("environments"));
//解析databaseIdProvider标签
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//解析typeHandlers标签
typeHandlerElement(root.evalNode("typeHandlers"));
//解析mappers标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
解析properties标签
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
//获取子标签的name value属性,封装为Properties对象
Properties defaults = context.getChildrenAsProperties();
//获取resource属性的值
String resource = context.getStringAttribute("resource");
//获取url属性的值
String url = context.getStringAttribute("url");
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
//读取配置文件的值,封装为Properties对象 加入到defaults 中。
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
//从configuration中获取variables
Properties vars = configuration.getVariables();
if (vars != null) {
//如果有值,添加到defaults中
defaults.putAll(vars);
}
//将parser的variables设置为defaults
parser.setVariables(defaults);
//将configuration的variables设置为defaults
configuration.setVariables(defaults);
}
}
解析name属性为logImpl的setting标签
private void loadCustomLogImpl(Properties props) {
//获取logImpl属性值,并且包装为class对象,这里的值可以不是一个类的完整限定名,而是一个别名
Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));
//将logImpl设置到configuration的logImpl属性中
configuration.setLogImpl(logImpl);
}
protected <T> Class<? extends T> resolveClass(String alias) {
if (alias == null) {
return null;
}
try {
//看这里
return resolveAlias(alias);
} catch (Exception e) {
throw new BuilderException("Error resolving class. Cause: " + e, e);
}
}
protected <T> Class<? extends T> resolveAlias(String alias) {
//看这里
return typeAliasRegistry.resolveAlias(alias);
}
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) {
return null;
}
// issue #748
//先转为小写
String key = string.toLowerCase(Locale.ENGLISH);
Class<T> value;
//Configuration对象实例化的时候(构造函数的具体逻辑),向typeAliases这个map中,放入了许多内置的值。
//比如typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);(注册的key会先转为小写)
if (typeAliases.containsKey(key)) {
//如果别名集合中含有该值,从取到对应的类
value = (Class<T>) typeAliases.get(key);
} else {
//没有,则直接调用classForName获取到class对象
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
public void setLogImpl(Class<? extends Log> logImpl) {
if (logImpl != null) {
//将logImpl设置到configuration的logImpl属性中
this.logImpl = logImpl;
LogFactory.useCustomLogging(this.logImpl);
}
}
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
setImplementation(clazz);
}
private static void setImplementation(Class<? extends Log> implClass) {
try {
//获取该日志类的构造函数
Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
Log log = candidate.newInstance(LogFactory.class.getName());
if (log.isDebugEnabled()) {
log.debug("Logging initialized using '" + implClass + "' adapter.");
}
//把该日志构造函数设置到LogFactory的logConstructor属性中
logConstructor = candidate;
} catch (Throwable t) {
throw new LogException("Error setting Log implementation. Cause: " + t, t);
}
typeAliases标签解析
private void typeAliasesElement(XNode parent) {
if (parent != null) {
//获取子标签
for (XNode child : parent.getChildren()) {
//获取package标签
if ("package".equals(child.getName())) {
//获取name属性,也就是包名
String typeAliasPackage = child.getStringAttribute("name");
//看这里
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
//配置的不是package,直接配置的别名和类的方式
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
//获取class对象
Class<?> clazz = Resources.classForName(type);
//别名没有配置
if (alias == null) {
//找类上的Alias注解,注解也没有,直接使用类的simpleName作为别名
typeAliasRegistry.registerAlias(clazz);
} else {
//注册别名和类的对应关系到typeAliases中
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}
public void registerAliases(String packageName) {
//Object类型
registerAliases(packageName, Object.class);
}
public void registerAliases(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
//找到该包下所有的class文件
//使用classLoader.loadClass获取对应class,如果是superType类型
//收集到resolverUtil的matches集合中
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
//获得resolverUtil的matches集合的类
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for (Class<?> type : typeSet) {
// Ignore inner classes and interfaces (including package-info.java)
// Skip also inner classes. See issue #6
//如果类的SimpleName不为空,不是接口 , 不是内部类
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
registerAlias(type);
}
}
}
public ResolverUtil<T> find(Test test, String packageName) {
//将配置的包名中的.替换为/
String path = getPackagePath(packageName);
try {
//VFS.getInstance(),静态内部类的方式实现的单例模式
//VFS主要用来读取当前应用程序的资源文件,默认有JBoss6VFS和DefaultVFS,loadCustomVfs方法会添加其他VFS的实现类
//找到所有的资源文件
List<String> children = VFS.getInstance().list(path);
for (String child : children) {
//如果以.class结尾
if (child.endsWith(".class")) {
addIfMatching(test, child);
}
}
} catch (IOException ioe) {
log.error("Could not read package: " + packageName, ioe);
}
return this;
}
protected void addIfMatching(Test test, String fqn) {
try {
//转换为类的完整限定名
String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
ClassLoader loader = getClassLoader();
if (log.isDebugEnabled()) {
log.debug("Checking to see if class " + externalName + " matches criteria [" + test + "]");
}
//使用类加载器加载该类
Class<?> type = loader.loadClass(externalName);
//使用的test为new ResolverUtil.IsA
//对应的matches为
//public boolean matches(Class<?> type) {
// return type != null && parent.isAssignableFrom(type);
//}
if (test.matches(type)) {
//添加到matches容器中
matches.add((Class<T>) type);
}
} catch (Throwable t) {
//加载不到,忽略
log.warn("Could not examine class '" + fqn + "'" + " due to a " +
t.getClass().getName() + " with message: " + t.getMessage());
}
}
public void registerAlias(Class<?> type) {
//alias为类的simpleName
String alias = type.getSimpleName();
//获取类的Alias注解的值
Alias aliasAnnotation = type.getAnnotation(Alias.class);
//注解不为空alias为注解配置的值
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
//注册别名和类的对应关系到typeAliases中
registerAlias(alias, type);
}
public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// issue #748
//将别名传为小写
String key = alias.toLowerCase(Locale.ENGLISH);
if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");
}
//放入typeAliases(map)中
typeAliases.put(key, value);
}
解析plugins标签
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
//获取子标签
for (XNode child : parent.getChildren()) {
//获取interceptor属性值(类名或者别名都可以)
String interceptor = child.getStringAttribute("interceptor");
//获取child 的 子标签的name和value值
Properties properties = child.getChildrenAsProperties();
//实例化拦截器类
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
//调用拦截器的setProperties 入参为 properties
interceptorInstance.setProperties(properties);
//将拦截器添加到configuration的interceptorChain的interceptors集合中
configuration.addInterceptor(interceptorInstance);
}
}
}
解析environments标签
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
//获取default属性赋值给environment属性
environment = context.getStringAttribute("default");
}
//循环所有的子标签environment
for (XNode child : context.getChildren()) {
//获取子标签environment的id属性
String id = child.getStringAttribute("id");
//如果id和environment相等
if (isSpecifiedEnvironment(id)) {
//解析environment标签的transactionManager标签
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//解析environment标签的dataSource标签
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
//设置txFactory,dataSource和id到environmentBuilder中
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
//将environmentBuilder.build()赋值给configuration的environment属性
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
//获取type属性,事务管理器的别名或者类名
String type = context.getStringAttribute("type");
//获取子标签的name和value属性封装为Properties
Properties props = context.getChildrenAsProperties();
//实例化事务管理器
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
//设置props的值到TransactionFactory 中
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
//获取type属性,数据源工厂的别名或者类名
String type = context.getStringAttribute("type");
//获取子标签的name和value属性封装为Properties
Properties props = context.getChildrenAsProperties();
//实例化数据源工厂
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
//设置props的值到DataSourceFactory 中
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
解析databaseIdProvider标签
private void databaseIdProviderElement(XNode context) throws Exception {
//<databaseIdProvider type="DB_VENDOR">
// <property name="Oracle" value="oracle"/>
// <property name="MySQL" value="mysql"/>
//</databaseIdProvider>
//oracle mysql这种值用于配置到mapper.xml中的databaseId属性中.
DatabaseIdProvider databaseIdProvider = null;
if (context != null) {
//获取 type属性值
String type = context.getStringAttribute("type");
// awful patch to keep backward compatibility
//如果配置的是VENDOR,则转为DB_VENDOR,都会用VendorDatabaseIdProvider类
//typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
if ("VENDOR".equals(type)) {
type = "DB_VENDOR";
}
//获取子标签的name和value值封装为properties
Properties properties = context.getChildrenAsProperties();
//实例化DatabaseIdProvider类型
databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
//设置properties属性值到databaseIdProvider中
databaseIdProvider.setProperties(properties);
}
//获取configuration的environment属性
Environment environment = configuration.getEnvironment();
if (environment != null && databaseIdProvider != null) {
//获取当前数据源对象对应property中的value值
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
//设置value值到configuration的databaseId中
configuration.setDatabaseId(databaseId);
}
}
public String getDatabaseId(DataSource dataSource) {
if (dataSource == null) {
throw new NullPointerException("dataSource cannot be null");
}
try {
//看这里
return getDatabaseName(dataSource);
} catch (Exception e) {
LogHolder.log.error("Could not get a databaseId from dataSource", e);
}
return null;
}
private String getDatabaseName(DataSource dataSource) throws SQLException {
//获取databaseProductName
String productName = getDatabaseProductName(dataSource);
if (this.properties != null) {
//循环配置的所有的properties值
for (Map.Entry<Object, Object> property : properties.entrySet()) {
//如果productName包含property的key,则返回property的value
if (productName.contains((String) property.getKey())) {
return (String) property.getValue();
}
}
// no match, return null
return null;
}
return productName;
}
private String getDatabaseProductName(DataSource dataSource) throws SQLException {
Connection con = null;
try {
//使用数据源对象获取连接对象
con = dataSource.getConnection();
DatabaseMetaData metaData = con.getMetaData();
//获取连接对象的DatabaseProductName , 比如 Oracle MySQL 等
return metaData.getDatabaseProductName();
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
// ignored
}
}
}
}
解析typeHandlers标签
private void typeHandlerElement(XNode parent) throws Exception {
if (parent != null) {
//获取子标签typeHandler或package
for (XNode child : parent.getChildren()) {
//获取package标签
if ("package".equals(child.getName())) {
//获取package标签的name属性1
String typeHandlerPackage = child.getStringAttribute("name");
//扫描包,并且注册typeHandle
typeHandlerRegistry.register(typeHandlerPackage);
} else {
//处理子标签typeHandler
String javaTypeName = child.getStringAttribute("javaType");
String jdbcTypeName = child.getStringAttribute("jdbcType");
String handlerTypeName = child.getStringAttribute("handler");
//可以配置别名,使用resolveClass获取到具体的类
Class<?> javaTypeClass = resolveClass(javaTypeName);
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
Class<?> typeHandlerClass = resolveClass(handlerTypeName);
//注册javaType和Map<JdbcType, TypeHandler<?>> map(jdbcType和TypeHandler的映射关系)的映射关系
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
public void register(String packageName) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
//扫描获取包路径下的所有TypeHandler类型的class
resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
//获取扫描到的所有的TypeHandler类
Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
for (Class<?> type : handlerSet) {
//Ignore inner classes and interfaces (including package-info.java) and abstract classes
if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
//注册
register(type);
}
}
}
public void register(Class<?> typeHandlerClass) {
boolean mappedTypeFound = false;
//获取MappedTypes注解
MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
if (mappedTypes != null) {
//循环MappedTypes注解的值,也就是对应的可以处理的java类型
for (Class<?> javaTypeClass : mappedTypes.value()) {
//注册
register(javaTypeClass, typeHandlerClass);
mappedTypeFound = true;
}
}
if (!mappedTypeFound) {
//注解没有值的一样可以注册
register(getInstance(null, typeHandlerClass));
}
}
private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
//获取MappedJdbcTypes注解
MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
if (mappedJdbcTypes != null) {
//循环MappedJdbcTypes注解的值,也就是对应的可以处理的jdbc类型
for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
//注册
register(javaType, handledJdbcType, typeHandler);
}
if (mappedJdbcTypes.includeNullJdbcType()) {
//注册
register(javaType, null, typeHandler);
}
} else {
//注册
register(javaType, null, typeHandler);
}
}
private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
if (javaType != null) {
//使用javaType获取到map
Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);
if (map == null || map == NULL_TYPE_HANDLER_MAP) {
map = new HashMap<>();
//注册javaType和Map<JdbcType, TypeHandler<?>> map的映射关系
typeHandlerMap.put(javaType, map);
}
//注册jdbcType和typeHndler的映射关系
map.put(jdbcType, handler);
}
//建立TypeHandler的class和TypeHandler的映射关系
allTypeHandlersMap.put(handler.getClass(), handler);
}
解析mappers标签
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
//获取子标签package或者mapper
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
//获取package标签的name属性
String mapperPackage = child.getStringAttribute("name");
//扫描包下的xml文件,解析加入到configuration中
//解析mapper的xml的代码和注解里面的指定的sql的代码较为繁琐这里就不详细展开了
//主要需要了解到:
//解析的resultMap标签的内容会加入configuration的resultMaps(Map)中,key为namespace加resultMap标签的id属性
//解析的sql内容最终包装为MappedStatement,加入到configuration的mappedStatements(map)中,key为namespace加自己标签的id属性
//将mapper的接口类型和生成的代理工厂类(MapperProxyFactory)注册到Configuration的mapperRegistry的knownMappers属性中(这个后续再详细说)
//knownMappers.put(type, new MapperProxyFactory<>(type));
configuration.addMappers(mapperPackage);
} else {
//处理mapper标签的属性
//读取到配置的xml文件
//解析加入到configuration中
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
public void parseStatementNode() {
//省略部分源码
//解析的sql内容包装为SqlSource
//一般有动态标签的则为DynamicSqlSource
//DynamicSqlSource含有configuration和rootSqlNode(解析出的sql内容,包装为了MixedSqlNode,里面持有其他的sqlNode节点,树状结构嵌套各个sqlNode(标签中包含sql或者换行空格或者其他标签))
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
//省略部分源码
//解析的sql包裝為MappedStatement,然后加入到configuration中
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
到此解析mybatis的xml配置文件的主要流程就结束了。