文章目录
Mybatis初始化(全局配置文件解析)
实际上就是读取解析mybatis-config.xml配置文件里面的各种标签,并创建一个 Configuration 对象,把配置文件中的内容存到 Configuration 对象中(可以看作mybatis工作所需的上下文,存储mybatis工作时所需要的信息),返回SqlSessionFactory(实际上返回的是其子类DefaultSqlSessionFactory对象),Configuration 对象是DefaultSqlSessionFactory的属性
@Test
void t1() throws IOException {
String resource = "mybatis-config.xml";
// getResourceAsStream方法内部通过classLoader加载mybatis-config.xml配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过 SqlSessionFactoryBuilder 创建 SqlSessionFactory 实例对象(解析mybatis-config.xml配置)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.queryById(1L);
System.out.println("user = " + user);
}
流程
1. 通过 Resources 类的 getResourceAsStream 方法加载全局配置文件 mybatis-config.xml
@Test
void t1() throws IOException {
String resource = "mybatis-config.xml";
// getResourceAsStream方法内部通过classLoader加载mybatis-config.xml配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 通过 SqlSessionFactoryBuilder 创建 SqlSessionFactory 实例对象(解析mybatis-config.xml配置)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.queryById(1L);
System.out.println("user = " + user);
}
2. SqlSessionFactory的build方法中创建XMLConfigBuilder对象用于构建Configuration对象
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
/**
* 核心build方法
*/
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 创建XMLConfigBuilder对象(XMLConfigBuilder构造方法创建了一个XPathParser对象用于解析xml配置文件)
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
...
}
}
2.1 XMLConfigBuilder构造方法
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
// 创建
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
2.1.1 XPathParser
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
// 将inputStream转为document
this.document = createDocument(new InputSource(inputStream));
}
2.2 在2.1中通过this调用另一个构造方法,此 构造方法中创建 Configuration 对象
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
// 创建Configuration对象
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
2.3 Configuration 对象构造方法
typeAliasRegistry向一个名为typeAliases的map注册别名,其实就是map.put(“alias”, Class)
languageRegistry注册使用的driver,告诉mybatis使用的哪种数据库
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
...
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
3. 调用parse()方法解析配置文件
/**
* 核心build方法
*/
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 创建XMLConfigBuilder对象(XMLConfigBuilder构造方法创建了一个XPathParser对象用于解析xml配置文件)
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 调用parse()方法解析配置文件,并返回Configuration(可以看作对前面创建的Configuration做属性填充)
return build(parser.parse());
...
}
}
3.1 parse方法解析配置文件标签
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
/*
解析全局配置文件mybatis-config.xml中的各种标签,存储到Configuration对象中
*/
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
// 解析properties标签
propertiesElement(root.evalNode("properties"));
// 解析settings标签
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
// typeAliases标签
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 此方法中如果没有解析到对应的配置,使用默认配置
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析mapper,放到Configuration对象中的一个map中,key为Class对象,value值为代理工厂
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
3.2 解析mappers标签
https://www.yuque.com/u5277/rxcryq/gb65gpcngxurkwyt
4. 调用 build 方法创建 SqlSessionFactory 并返回
public SqlSessionFactory build(Configuration config) {
// Configuration 存储在 DefaultSqlSessionFactory 中
return new DefaultSqlSessionFactory(config);
}