今天来看下Configuration这个类,顾名思义,它就是配置的意思,所有mybatis配置相关的信息都在里面能找到,是一个很重要的类,到底有多重要呢?你可以看到mybatis里面sqlsession和sqlsessionFactory这两个重要的接口里面都有getConfiguration的方法定义,我粗略看了下,感觉整个mybatis框架流转都会经过它(没经过验证,不一定对)。它里面持有了很多重要的属性,比如我们常用的typeAliasRegistry,mappedStatements,interceptorChain,mapperRegistry等都在里面。
我们知道,mybatis是通过加载配置完成整个sqlsessionFactory的创建,最后得到sqlsession的。所以mybatis的所有数据初始化都是根据Configuration来的,所以弄明白Configuration的工作原理对理解整个框架实现很有帮助,我们先从构造函数入手。
构造函数
可以看到构造函数有两种,无参的传入enviroment的。无参构造就是一些类型别名初始化。
TypeAliasRegistry
这里简单说下TypeAliasRegistry这个类,它的作用其实很简单,就是进行类型别名替换,我们在mybatis的xml文件配置的时候,都需要为其指定一个具体类型,类型必须是全路径,这样写起来很麻烦,如果多处使用那就要写好多次,这个类的作用就是解决这个问题,你只需要自己设置一个别名,然后直接使用别名就可以。
它里面持有一个typeAliases的Map,用来存储类型映射。可以看到它的构造函数其实一开始初始化了很多类型,这些你都直接可以在xml的type里面直接输入,可以看到都是一些基本类型和基本类型数组,还有date这些常用类型。
当然它在读取mybatis-config.xml的时候会将里面定义的type都注册进去。对应的是typeAliases这个标签。入口是在XMLConfigBuilder.typeAliasesElement
方法,有兴趣可以自己去看下。
为了支持注解,它在实际注册类的时候会先拿到注解Alias里的值,然后再进行赋值。
public void registerAlias(Class<?> type) {
String alias = type.getSimpleName();
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
registerAlias(alias, type);
}
底层逻辑是如果有设置别名,就直接用别名赋值,没有使用,直接用类名小写赋值。
看源码的时候突然我想到一个问题,如果在xml和注解同时设置了不同的别名,那最后是哪个生效呢?
我特意去看了下源码,主要取决于你利用什么配置生成的sqlsessionFacoty,如果是用的myabtis-config.xml生成,且没有使用package标签,那么注解生效。如果没有使用package标签,那么xml里面配置的生效。
在具体解析别名的时候拿到key去拿到对应类型,如果没有key,直接根据路径解析,在没有就会抛出异常。
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) {
return null;
}
// issue #748
String key = string.toLowerCase(Locale.ENGLISH);
Class<T> value;
if (typeAliases.containsKey(key)) {
value = (Class<T>) typeAliases.get(key);
} else {
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
Environment
我们在使用Configuration时,如果不是读入的mybatis-config.xml时,很多时候是自己构造Configuration,这时候就需要传入Environment,那么这个类具体是干嘛的呢?
首先看看它的属性有哪些,看了下就下面三个属性:
private final String id;
private final TransactionFactory transactionFactory;
private final DataSource dataSource;
那其实就很简单了,Environment就是环境抽象,比如我们的dev,test,prod这种,每个环境会对应一个数据源和事务信息。
所以我们构造一个Configuration的步骤是
总结
今天简单看了下Configuration的构造函数,介绍了下构造函数里用到的两个类TypeAliasRegistry和Environment的作用。
最后简单梳理下如果我们不读取配置文件的流,而是要自己全部用java代码构建一个Sqlsession需要哪些东西呢?
- 构造Environment:构造数据源,有事务要求的话构造事务,在设定环境标识(id)
- 构造Configuration:利用前面创建的Environment构造Configuration
- 构造SqlsessionFacoty:利用sqlsessionFactoryBuilder和前面创建的Configuration构建SqlsessionFactory
- 构造Sqlsession:利用SqlsessionFacoty的openSession拿到sqlsession
拿到sqlsession之后你就可以愉快的操作mapper进行CRUD了。
明天我们继续看Configuration,敬请期待。