目录
加载mapper.xml的过程实际上就是一个填充 Configuration 对象数据的过程,如下图将xml里面的所有属性一一对应到类Configuration
本节介绍如何创建SqlSessionFactory,深度解析内部的内容
阅读本文需要熟悉jdk的xml解析相关内容
先来一段我们熟悉的加载SqlSessionFactory
的代码
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
这里我们第一步来分析如何创建的SqlSessionFactory
org.apache.ibatis.session.SqlSessionFactoryBuilder
//第一步
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
//第二步,创建并填充Configuration
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
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.
}
}
}
// 第三部 返回SqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
宏观的说: 我们已经解读了SqlSessionFactory
的实现对象。 它的内部只有一个Configuration
对象
分析Configuration的创建过程就得分析XMLConfigBuilder
xml配置构建器
org.apache.ibatis.session.SqlSessionFactoryBuilder
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
分析构造 XMLConfigBuilder
org.apache.ibatis.builder.xml.XMLConfigBuilder
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
这里就是解读XMLConfigBuilder有哪些字段
1. Configuration
2. 填充configuration的variables //new SqlSessionFactoryBuilder().build(inputStream,props);
3. 标记解析状态为未解析
4. 环境变量
5. xpath解析器
org.apache.ibatis.session.SqlSessionFactoryBuilder
parser.parse()
org.apache.ibatis.builder.xml.XMLConfigBuilder
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
Configuration
对象的属性parser.evalNode(“/configuration”) 的详细内容参见parser解析器和XNode介绍
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
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"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
这里就已经把mybatis.xml的根节点configuration
的所有子节点填充到类Configuration
里面了
org.apache.ibatis.builder.xml.XMLConfigBuilder
//propertiesElement(root.evalNode("properties"));
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
// properties 节点的所有子节点
Properties defaults = context.getChildrenAsProperties();
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
// 同时存在url和resource,mybatis就蒙了
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.");
}
//填充指定resource
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
//填充指定url
defaults.putAll(Resources.getUrlAsProperties(url));
}
// 在 new SqlSessionFactoryBuilder().build(inputStream,vars); 指定的vars
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
//刷新XPathParser的vars
parser.setVariables(defaults);
//刷新configuration的vars
configuration.setVariables(defaults);
}
}
填充属性configuration.variables
org.apache.ibatis.builder.xml.XMLConfigBuilder
//typeAliasesElement(root.evalNode("typeAliases"));
private void typeAliasesElement(XNode parent) {
if (parent != null) {
// 遍历 typeAliases 的所有子节点
for (XNode child : parent.getChildren()) {
// 包扫描填充
if ("package".equals(child.getName())) {
String typeAliasPackage = child.getStringAttribute("name");
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
Class> clazz = Resources.classForName(type);
// 只有type时,从clazz获取Alias注解的value为别名
//
//@Alias("blogMapper")
//public interface BlogMapper {}
if (alias == null) {
typeAliasRegistry.registerAlias(clazz);
} else {
// 直接指定别名
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}
填充属性configuration.typeAliasRegistry
org.apache.ibatis.builder.xml.XMLConfigBuilder
//pluginElement(root.evalNode("plugins"));
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
// 遍历 plugins 子节点
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
// 创建属性 interceptor="com.aya.BlogInterceptor" 指定的类,必须实现接口Interceptor
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
// 填充属性
//
//
//
//
//
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
填充属性 configuration.interceptorChain
org.apache.ibatis.builder.xml.XMLConfigBuilder
// objectFactoryElement(root.evalNode("objectFactory"));
private void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties properties = context.getChildrenAsProperties();
ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
factory.setProperties(properties);
configuration.setObjectFactory(factory);
}
}
// objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
private void objectWrapperFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
configuration.setObjectWrapperFactory(factory);
}
}
// reflectorFactoryElement(root.evalNode("reflectorFactory"));
private void reflectorFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
configuration.setReflectorFactory(factory);
}
}
上述代码都是一样的,创建对象并填充对应的属性
org.apache.ibatis.builder.xml.XMLConfigBuilder
// typeHandlerElement(root.evalNode("typeHandlers"));
private void typeHandlerElement(XNode parent) throws Exception {
if (parent != null) {
// 遍历typeHandlers子节点
for (XNode child : parent.getChildren()) {
//扫描包的所有类,注册类型处理器
if ("package".equals(child.getName())) {
String typeHandlerPackage = child.getStringAttribute("name");
typeHandlerRegistry.register(typeHandlerPackage);
} else {
//单个指定注册
String javaTypeName = child.getStringAttribute("javaType");
String jdbcTypeName = child.getStringAttribute("jdbcType");
String handlerTypeName = child.getStringAttribute("handler");
Class> javaTypeClass = resolveClass(javaTypeName);
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
Class> typeHandlerClass = resolveClass(handlerTypeName);
// javaType 和 typeHandlerClass 必须都存在
if (javaTypeClass != null) {
if (jdbcType == null) {
// xml指定了javaType,handler
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
// xml指定了javaType,jdbcType,handler
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
// 获取类的注解 MappedTypes,作为javaType进行注册
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
//Properties settings = settingsAsProperties(root.evalNode("settings"));
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
}
//解析settings的所有子节点为Properties对象
Properties props = context.getChildrenAsProperties();
// Check that all settings are known to the configuration class
//获取Configuration的元数据
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
for (Object key : props.keySet()) {
//进行setter验证
//
// 验证成功,configuration存在 setUseGeneratedKeys 方法
// 验证失败,configuration存在 setHahahaha 方法
//
if (!metaConfig.hasSetter(String.valueOf(key))) {
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
}
}
return props;
}
这里并没有对configuration进行填充
//settingsElement(settings);
private void settingsElement(Properties props) throws Exception {
configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
// 省略填充
}
将 settings
子节点的Properties对象填充到configuration
这里的内容太多,将单独详解mapper的填充
org.apache.ibatis.builder.xml.XMLConfigBuilder
//SqlSessionFactoryBuilder 里面的 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
org.apache.ibatis.parsing.XPathParser
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
// 载入文档
this.document = createDocument(new InputSource(inputStream));
}
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
// 创建xpath
XPathFactory factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
}
XPathParser 就是根节点
和xml获取节点
的一个封装
org.apache.ibatis.parsing.XNode
public XNode(XPathParser xpathParser, Node node, Properties variables) {
//parser解析器
this.xpathParser = xpathParser;
// 当前节点
this.node = node;
// 当前节点名词
this.name = node.getNodeName();
// 属性
this.variables = variables;
//解析节点的所有属性为Properties
this.attributes = parseAttributes(node);
//body 字符串
this.body = parseBody(node);
}
一个封装 Node 访问的一个类
org.apache.ibatis.builder.xml.XMLConfigBuilder
MetaClass.forClass(Configuration.class, localReflectorFactory);
将Class注册到元数据工厂
,然后返回元数据。
元数据到底是什么呢?
// 创建元数据
public static MetaClass forClass(Class> type, ReflectorFactory reflectorFactory) {
return new MetaClass(type, reflectorFactory);
}
//注册中心获取 反射数据
private MetaClass(Class> type, ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
this.reflector = reflectorFactory.findForClass(type);
}
元数据包含了两个内容
1. 反射工厂
2. class的反射信息
org.apache.ibatis.reflection.ReflectorFactory
//
@Override
public Reflector findForClass(Class> type) {
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
Reflector cached = reflectorMap.get(type);
if (cached == null) {
cached = new Reflector(type);
reflectorMap.put(type, cached);
}
return cached;
} else {
return new Reflector(type);
}
}
反射工厂 findForClass 用缓存的方式,缓存了Class
对应的Reflector
public Reflector(Class> clazz) {
type = clazz;
addDefaultConstructor(clazz);
addGetMethods(clazz);
addSetMethods(clazz);
addFields(clazz);
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
这里已经可以分析出反射信息的内容了
1. class 所有的 setter
方法
2. class 所有的 getter
方法
3. class 所有的 字段
4. class 所有的 构造
5. class 所有的 setter 参数类型
6. class 所有的 getter 返回值类型
7. class 所有的 setter 的忽略大小写
8. class 所有的 getter 的忽略大小写
有了这些内容就可以快速判断方法的存在性
,类型一致性