在MyBatis初始化过程中,大致有以下几个步骤:分解所有IT类编制
创建Configuration全局配置对象时,TypeAliasRegistry别名注册中心将添加Mybatis所需的相关类,并将基于语言的默认类设置为加载XMLLanguageDriver的myba配置文件、Mapper界面的详图索引信息和XML映射文件。解析的配置信息构成相应的对象,并存储在Configuration全局配置对象中。构建DefaultSqlSessionFactory对象可以创建DefaultSqlSession对象。MyBatis的SqlSession的默认实现类在整个初始化过程中包含更多代码。
由于在《MyBatis初始化(一)之加载myba》 《MyBatis初始化(二)之加载Mapper接口与XML映射文件》 《MyBatis初始化(三)之SQL初始化(上)》 《MyBatis初始化(四)之SQL初始化(下)》 MyBatis初始化期间解析Mapper接口与XML映射文件相关的篇幅很多,XML映射文件的解析过程也很复杂,因此分为以下三个模块,逐步分析,易于理解。
初始化(b)加载映射接口和映射文件
上一个模块分析了如何解析myba配置文件。最后,尚未分析解析Mapper/标签的方法。这个过程比较复杂,因为需要解析映射程序接口和XML映射文件。让我们看一下这个解析过程
解析XML映射文件生成的对象主要如下图所示。
默认程序包路径:org.a、org.a
主要涉及的类:
Org.a.XML.XMLConfigBuilder:解析配置文件,开始初始化Mapper接口和XML映射文件,创建Configuration全局配置对象org.a:Mapper接口注册中心,Mapper这里我们解析的Mapper接口是org . a . apperorg.a.XML.XMLMapperBuilder:剖析XML映射文件org.a.xml.XMLStatementBuilder:剖析XML Delete/insert/标签)org.a. mapperbuilderassistant也就是说,Java类型和JDBC类型之间的映射信息org.a.ResultMap: resultMap/标记的配置信息和存储子标记的所有信息org.a.MappedStatement:解析select/upps
让我们回顾一下前面的模块。org.a.xml.XMLConfigBuilder解析myba配置文件中的mapper/标记,并调用parse()-parse configuration(xnode roon)
private void mapper element(xnode parent)throws exception {
If(零件!=空){
//0通过子节点
For (xnodechild3360 ()) {
//1如果是package标签,请扫描包
If ('package ')。equal(){
//获取软件包名称
字串mapper package=c(' name ');
//添加到配置
CON(MAPPERPACKAGE);
}如果是else {//mapper标签
获取//resource、URL和class属性
string resource=c(' resource ');
字串URL=c(' URL ');
字串mapper class=c(' class ');
//2使用相对于类路径的资源引用
If(资源!=null URL==null mapper class==null){
ErrorCon()。资源(资源);
从//resource导入InputStream对象
Inputstream inputstream=re(资源);
//创建XMLMapperBuilder对象
xmlmapperbuildermapperparser=new xmlmapperbuilder(input stream、configuration、resource、con());
//执行解决
MA();
//3使用完全限定的资源定位器(URL)
} else if (resource==空URL!=空映射类==空){
ErrorCon()。资源(URL);
获取//URL的InputStream对象
InputStream InputStream=Re(URL);
//创建XMLMapperBuilder对象
xmlmapperbuildermapperparser=new xmlmapperbuilder(input stream、configuration、URL、con());
//执行解决
MA();
//4使用映射程序接口实现类的完全限定类名
} else if(resource==null URL==null mapper class!=空){
//Mapper接口导入
班级?mapper interface=Re(mapper class);
//添加到配置
地图界面(con);
} else {
throw new builder exception(' a mapper element may only specify a URL,resource or class,but not more than one . '));
}
}
}
}
}
遍历Mapper/标记的子节点
对于Package/子节点,导入解析包路径下Mapper接口的Package属性后,通过子节点的resource属性或URL属性解析映射文件,或通过class属性解析Mapper接口,通常会直接配置包路径,因此可以看到上面的第一对
首先,将软件包软件包路径添加到Configuration全局配置对象中。也就是说,通过调用调用内部MapperRegistry注册表和MapperRegistry的addMappers(字符串包名)方法进行注册
让我们看一下如何在MapperRegistry注册表中解析。此类在上一文档的Binding模块中解释如下:
Public class MapperRegistry {
public void add mappers(string package name){
Addmappers(软件包名称,object . class);
}
/* *
*用于在指定软件包中搜索Mapper接口并将其绑定到XML文件
* @since 3.2.2
*/
public void add mappers(string package name,class?SuperType) {
//1搜索指定程序包下的指定类
ResolverUtilClass?ResolverUtil=new ResolverUtil();
Re (new re (supertype),package name);
SetClass?Extends Class?MapperSet=re();
//2巡回,添加到knownMappers
For(类?MapperClass : mapperSet) {
add mapper(mapper class);
}
}
public t void add mapper(class type){
//1判断,必须是接口。
if ()) {
// <2> 已经添加过,则抛出 BindingException 异常
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
// <3> 将Mapper接口对应的代理工厂添加到 knownMappers 中
knownMa(type, new MapperProxyFactory<>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the mapper parser.
// If the type is already known, it won't try.
// <4> 解析 Mapper 的注解配置
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
// 解析 Mapper 接口上面的注解和 Mapper 接口对应的 XML 文件
();
// <5> 标记加载完成
loadCompleted = true;
} finally {
// <6> 若加载未完成,从 knownMappers 中移除
if (!loadCompleted) {
knownMa(type);
}
}
}
}
}
<1>首先必须是个接口
<2>已经在MapperRegistry注册中心存在,则会抛出异常
<3>创建一个Mapper接口对应的MapperProxyFactory动态代理工厂
<4>【重要!!!】通过MapperAnnotationBuilder解析该Mapper接口与对应XML映射文件
MapperAnnotationBuilder
org.a.annotation.MapperAnnotationBuilder:解析Mapper接口,主要是解析接口上面注解,加载XML文件会调用XMLMapperBuilder类进行解析
我们先来看看他的构造函数和parse()解析方法:
public class MapperAnnotationBuilder {
/**
* 全局配置对象
*/
private final Configuration configuration;
/**
* Mapper 构造器小助手
*/
private final MapperBuilderAssistant assistant;
/**
* Mapper 接口的 Class 对象
*/
private final Class<?> type;
public MapperAnnotationBuilder(Configuration configuration, Class<?> type) {
String resource = ().replace('.', '/') + ".java (best guess)";
= new MapperBuilderAssistant(configuration, resource);
= configuration;
= type;
}
public void parse() {
String resource = ();
if (!con(resource)) {
// 加载该接口对应的 XML 文件
loadXmlResource();
con(resource);
a(());
// 解析 Mapper 接口的 @CacheNamespace 注解,创建缓存
parseCache();
// 解析 Mapper 接口的 @CacheNamespaceRef 注解,引用其他命名空间
parseCacheRef();
Method[] methods = ();
for (Method method : methods) {
try {
// issue #237
if (!me()) { // 如果不是桥接方法
// 解析方法上面的注解
parseStatement(method);
}
} catch (IncompleteElementException e) {
con(new MethodResolver(this, method));
}
}
}
parsePendingMethods();
}
private void loadXmlResource() {
// Spring may not know the real resource name so we check a flag
// to prevent loading again a resource twice
// this flag is set at XMLMapperBuilder#bindMapperForNamespace
if (!con("namespace:" + ())) {
String xmlResource = ().replace('.', '/') + ".xml";
// #1347
InputStream inputStream = ("/" + xmlResource);
if (inputStream == null) {
// Search XML mapper that is not in the module but in the classpath.
try {
inputStream = Re(), xmlResource);
} catch (IOException e2) {
// ignore, resource is not required
}
}
if (inputStream != null) {
// 创建 XMLMapperBuilder 对象
XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, a(),
xmlResource, con(), ());
// 解析该 XML 文件
xmlPar();
}
}
}
}
在构造函数中,会创建一个MapperBuilderAssistant对象,Mapper 构造器小助手,用于创建XML映射文件中对应相关对象
parse()方法,用于解析Mapper接口:
- 获取Mapper接口的名称,例如in,根据Configuration全局配置对象判断该Mapper接口是否被解析过
- 没有解析过则调用loadXmlResource()方法解析对应的XML映射文件
- 然后解析接口的@CacheNamespace和@CacheNamespaceRef注解,再依次解析方法上面的MyBatis相关注解
注解的相关解析这里就不讲述了,因为我们通常都是使用XML映射文件,逻辑没有特别复杂,都在MapperAnnotationBuilder中进行解析,感兴趣的小伙伴可以看看
1.《如何初始化接口?终于找到答案了MyBatis初始化加载 Mapper 接口与XML文件》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《如何初始化接口?终于找到答案了MyBatis初始化加载 Mapper 接口与XML文件》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/gl/2093880.html