1.properties标签解析
private void propertiesElement(XNode context) throws Exception {
//context :<properties resource="org/apache/ibatis/databases/blog/blog-derby.properties" />
if (context == null) {
return;
}
Properties defaults = context.getChildrenAsProperties();
//获取resource属性值
String resource = context.getStringAttribute("resource");
//获取url属性值
String url = context.getStringAttribute("url");
//url和resource对应的资源文件不能同时指定
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.");
}
if (resource != null) {
//加载resource资源文件信息到defaults中
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
//加载url资源文件信息到defaults中
defaults.putAll(Resources.getUrlAsProperties(url));
}
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
//最终设置到Configuration 对象 protected Properties variables = new Properties()中
//解析 <properties resource="org/apache/ibatis/databases/blog/blog-derby.properties"/>标签完成
configuration.setVariables(defaults);
}
<!ELEMENT properties (property*)>
<!ATTLIST properties
resource CDATA #IMPLIED
url CDATA #IMPLIED
>
从dtd文件可以看出,properties有url(绝对路径)和resource(相对路径)两个属性。 最终设置到Configuration 对象 protected Properties variables = new Properties()中
2.settings标签解析
private Properties settingsAsProperties(XNode context) {
/**
* context :
* <settings>
* <setting name="cacheEnabled" value="true" />
* <setting name="lazyLoadingEnabled" value="false" />
* <setting name="multipleResultSetsEnabled" value="true" />
* <setting name="useColumnLabel" value="true" />
* <setting name="useGeneratedKeys" value="false" />
* <setting name="defaultExecutorType" value="SIMPLE" />
* <setting name="defaultStatementTimeout" value="25" />
* </settings>
*/
if (context == null) {
return new Properties();
}
//把标签里面的name和value值放到Properties中
Properties props = context.getChildrenAsProperties();
// Check that all settings are known to the configuration class
//校验setting里面配置name属性值要在Configuration中定义。也就是自己随意定义的name值是不行的
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
for (Object key : props.keySet()) {
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;
}
解析settings标签成Properties对象
3.typeAliases 别名配置解析
private void typeAliasesElement(XNode context) {
/**
* context:
* <typeAliases>
* <typeAlias alias="Author" type="org.apache.ibatis.domain.blog.Author" />
* <typeAlias alias="Blog" type="org.apache.ibatis.domain.blog.Blog" />
* <typeAlias alias="Comment" type="org.apache.ibatis.domain.blog.Comment" />
* <typeAlias alias="Post" type="org.apache.ibatis.domain.blog.Post" />
* <typeAlias alias="Section" type="org.apache.ibatis.domain.blog.Section" />
* <typeAlias alias="Tag" type="org.apache.ibatis.domain.blog.Tag" />
* </typeAliases>
*/
if (context == null) {
return;
}
for (XNode child : context.getChildren()) {
if ("package".equals(child.getName())) {
String typeAliasPackage = child.getStringAttribute("name");
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
//获取alias属性值
String alias = child.getStringAttribute("alias");
//获取type属性值
String type = child.getStringAttribute("type");
try {
/**
* 注册到
*TypeAliasRegistry
* private final Map<String, Class<?>> typeAliases = new HashMap<>();
*/
Class<?> clazz = Resources.classForName(type);
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);
}
}
}
}
4.plugins插件标签解析
private void pluginsElement(XNode context) throws Exception {
/**
* context:
* <plugins>
* <plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">
* <property name="pluginProperty" value="100" />
* </plugin>
* </plugins>
*/
if (context != null) {
for (XNode child : context.getChildren()) {
//获取<plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">interceptor属性值
String interceptor = child.getStringAttribute("interceptor");
//获取 <property name="pluginProperty" value="100" /> name,value属性值
Properties properties = child.getChildrenAsProperties();
//根据interceptor值反射获取Interceptor实例
//如果TypeAliasRegistry private final Map<String, Class<?>> typeAliases = new HashMap<>();中存在,则从中获取
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor()
.newInstance();
//设置到properties中
interceptorInstance.setProperties(properties);
//添加到Configuration protected final InterceptorChain interceptorChain = new InterceptorChain();拦截器chain中
configuration.addInterceptor(interceptorInstance);
}
}
}
解析完成添加到Configuration对象 protected final InterceptorChain interceptorChain = new InterceptorChain()中
5.objectFactory标签解析
private void objectFactoryElement(XNode context) throws Exception {
/**
* context:
* <objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory">
* <property name="objectFactoryProperty" value="100" />
* </objectFactory>
*/
if (context != null) {
// 获取<objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory"> type属性值
String type = context.getStringAttribute("type");
//获取<property name="objectFactoryProperty" value="100" /> name,value属性值
Properties properties = context.getChildrenAsProperties();
//由type值反射获取ObjectFactory实例。
//若TypeAliasRegistry private final Map<String, Class<?>> typeAliases = new HashMap<>();
//中存在,则从中获取
ObjectFactory factory = (ObjectFactory) resolveClass(type).getDeclaredConstructor().newInstance();
//设置properties中
factory.setProperties(properties);
//设置Configuration protected ObjectFactory objectFactory = new DefaultObjectFactory();中
configuration.setObjectFactory(factory);
}
解析完成,添加到Configuration protected ObjectFactory objectFactory = new DefaultObjectFactory()中
6.objectWrapperFactory标签解析
private void objectWrapperFactoryElement(XNode context) throws Exception {
if (context != null) {
//获取属性值type
String type = context.getStringAttribute("type");
//由type反射获取ObjectWrapperFactory
ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).getDeclaredConstructor().newInstance();
//设置到Configuration protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();中
configuration.setObjectWrapperFactory(factory);
}
}
解析成,添加到Configuration对象 protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory()中
7.reflectorFactory标签解析
private void reflectorFactoryElement(XNode context) throws Exception {
if (context != null) {
//获取属性值type
String type = context.getStringAttribute("type");
//由type反射获取ReflectorFactory
ReflectorFactory factory = (ReflectorFactory) resolveClass(type).getDeclaredConstructor().newInstance();
//设置到Configuration protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();中
configuration.setReflectorFactory(factory);
}
}
8.environments标签解析
private void environmentsElement(XNode context) throws Exception {
/**
* context:
* <environments default="development">
* <environment id="development">
* <transactionManager type="JDBC">
* <property name="" value=""/>
* </transactionManager>
* <dataSource type="UNPOOLED">
* <property name="driver" value="${driver}"/>
* <property name="url" value="${url}"/>
* <property name="username" value="${username}"/>
* <property name="password" value="${password}"/>
* </dataSource>
* </environment>
* </environments>
*/
if (context == null) {
return;
}
if (environment == null) {
// <environments default="development">
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
// <environment id="development">
String id = child.getStringAttribute("id");
//判断environment值和id是否相同
//因为 <environments default="development">可以有多个子标签,取
//子标签<environment id="development">的id属性值等于default属性值
if (isSpecifiedEnvironment(id)) {
//获取TransactionFactory
//<transactionManager type="JDBC">
// <property name="" value=""/>
//</transactionManager>
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//获取DataSourceFactory
//<dataSource type="UNPOOLED">
// <property name="driver" value="${driver}"/>
// <property name="url" value="${url}"/>
// <property name="username" value="${username}"/>
// <property name="password" value="${password}"/>
//</dataSource>
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
//构建Environment对象
Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory)
.dataSource(dataSource);
//设置到Configuration protected Environment environment; 中
configuration.setEnvironment(environmentBuilder.build());
break;
}
}
}
9.databaseIdProvider标签解析
private void databaseIdProviderElement(XNode context) throws Exception {
if (context == null) {
return;
}
String type = context.getStringAttribute("type");
// awful patch to keep backward compatibility
if ("VENDOR".equals(type)) {
type = "DB_VENDOR";
}
//获取name,value属性值
Properties properties = context.getChildrenAsProperties();
//根据type属性值构建DatabaseIdProvider实例
DatabaseIdProvider databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor()
.newInstance();
databaseIdProvider.setProperties(properties);
Environment environment = configuration.getEnvironment();
if (environment != null) {
//根据Environment DataSource 获取databaseId
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
//设置databaseId
configuration.setDatabaseId(databaseId);
}
}
10.typeHandlers标签解析
private void typeHandlersElement(XNode context) {
/**
* context:
* <typeHandlers>
* <typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
* </typeHandlers>
*/
if (context == null) {
return;
}
for (XNode child : context.getChildren()) {
if ("package".equals(child.getName())) {
String typeHandlerPackage = child.getStringAttribute("name");
typeHandlerRegistry.register(typeHandlerPackage);
} else {
// <typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
//获取javaType属性值
String javaTypeName = child.getStringAttribute("javaType");
//获取jdbcType属性值
String jdbcTypeName = child.getStringAttribute("jdbcType");
//获取handler属性值
String handlerTypeName = child.getStringAttribute("handler");
Class<?> javaTypeClass = resolveClass(javaTypeName);
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
//根据handler属性值,反射构建实例
//org.apache.ibatis.builder.CustomStringTypeHandler
Class<?> typeHandlerClass = resolveClass(handlerTypeName);
//注册TypeHandlerRegistry,注册到对应集合中,方便后续调用
// private final Map<JdbcType, TypeHandler<?>> jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class);
// private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
// private final TypeHandler<Object> unknownTypeHandler;
// private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();
//
// private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = Collections.emptyMap();
//
// private Class<? extends TypeHandler> defaultEnumTypeHandler = EnumTypeHandler.class;
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
11.mappers标签解析
<mappers >
<!-- <package name="xxx.xxx"/>
<mapper class="xxx"/>
<mapper url="xxx"/>-->
<mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/>
<mapper resource="org/apache/ibatis/builder/BlogMapper.xml"/>
<mapper resource="org/apache/ibatis/builder/CachedAuthorMapper.xml"/>
<mapper resource="org/apache/ibatis/builder/PostMapper.xml"/>
<mapper resource="org/apache/ibatis/builder/NestedBlogMapper.xml"/>
</mappers>
根据配置的不同标签属性,获取xml资源文件
rosourde:相对路径
url:绝对路径
class:单个接口
package:包
虽然获取资源的方式不同,但结果都是把xml配文件里面的信息加载到Configuration对象的 属性字段中。
private void mappersElement(XNode context) throws Exception {
/**
* context:
* <mappers>
* <mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/>
* <mapper resource="org/apache/ibatis/builder/BlogMapper.xml"/>
* <mapper resource="org/apache/ibatis/builder/CachedAuthorMapper.xml"/>
* <mapper resource="org/apache/ibatis/builder/PostMapper.xml"/>
* <mapper resource="org/apache/ibatis/builder/NestedBlogMapper.xml"/>
* </mappers>
*/
if (context == null) {
return;
}
for (XNode child : context.getChildren()) {
//package
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
//<mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/>
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
//resource加载方式
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource,
configuration.getSqlFragments());
mapperParser.parse();
}
}
//url加载方式
else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
try (InputStream inputStream = Resources.getUrlAsStream(url)) {
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url,
configuration.getSqlFragments());
mapperParser.parse();
}
}
//mapperClass加载方式
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.");
}
}
}
}
parse()方法
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
//<mapper />
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
//绑定namespace接口类型和MapperProxyFactory
//例如 AuthorMapper 和 AuthorMapper.xml
bindMapperForNamespace();
}
configuration.parsePendingResultMaps(false);
configuration.parsePendingCacheRefs(false);
configuration.parsePendingStatements(false);
}
configurationElement()方法
解析xml文件中的所有标签,并加载到Configuration对象的属性字段中
private void configurationElement(XNode context) {
try {
//<mapper namespace="org.apache.ibatis.domain.blog.mappers.AuthorMapper">
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.isEmpty()) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
//添加缓存对象
//Configuration protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
cacheRefElement(context.evalNode("cache-ref"));
//解析cache属性值
//Configuration protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
cacheElement(context.evalNode("cache"));
//解析 <parameterMap id="selectAuthor" type="org.apache.ibatis.domain.blog.Author">
// <parameter property="id" />
// </parameterMap>
//标签
//添加到Configuration protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//解析 <resultMap id="selectAuthor" type="org.apache.ibatis.domain.blog.Author">
// <id column="id" property="id" />
// <result property="username" column="username" />
// <result property="password" column="password" />
// <result property="email" column="email" />
// <result property="bio" column="bio" />
// <result property="favouriteSection" column="favourite_section" />
// </resultMap>
//标签
//添加到添加到Configuration protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
resultMapElements(context.evalNodes("/mapper/resultMap"));
//解析sql片段
sqlElement(context.evalNodes("/mapper/sql"));
//解析select|insert|update|delete标签
//添加到添加到添加到Configuration protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
// "Mapped Statements collection")
// .conflictMessageProducer((savedValue, targetValue) -> ". please check " + savedValue.getResource() + " and "
// + targetValue.getResource());
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
bindMapperForNamespace()
把namespace和MapperProxyFactory进行绑定
private void bindMapperForNamespace() {
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class<?> boundType = null;
try {
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
// ignore, bound type is not required
}
if (boundType != null && !configuration.hasMapper(boundType)) {
// Spring may not know the real resource name so we set a flag
// to prevent loading again this resource from the mapper interface
// look at MapperAnnotationBuilder#loadXmlResource
configuration.addLoadedResource("namespace:" + namespace);
//添加到Configuration protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
configuration.addMapper(boundType);
}
}
}
总结
-
主要完成了config配置文件,mapper文件,mapper接口的解析和注册
-
获取一个Confinguratin对象,里面包含各种配置和一些容器对象