mybatis 之 mapper
·
目录
一、mapper解析
1、入口
private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
//解析mapper标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
2、解析
// XMLConfigBuilder.mapperElement
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
//resource配置方式走这里
ErrorContext.instance().resource(resource);
//根据路径读取文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//生成xmlMapperBuilder对象
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
//解析
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
//rul配置方式走这里
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
//mapperClass方式走这里
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.");
}
}
}
}
}
//XmlMapperBuilder.parse()
public void parse() {
//判断是否已经加载过
if (!configuration.isResourceLoaded(resource)) {
// xml -> configuration
configurationElement(parser.evalNode("/mapper"));
// 加入到已解析列表
configuration.addLoadedResource(resource);
//绑定命名空间
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingChacheRefs();
parsePendingStatements();
}
//解析mapper及子孙标签
//XmlMapperBuilder.configurationElement
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
//缓存的引用
cacheRefElement(context.evalNode("cache-ref"));
//缓存
cacheElement(context.evalNode("cache"));
//参数
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//返回结果
resultMapElements(context.evalNodes("/mapper/resultMap"));
//解析sql片段
sqlElement(context.evalNodes("/mapper/sql"));
//解析 select|insert|update|delete 这几个标签
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
具体的解析select|insert|update|delete 标签
//XmlMapperBuilder.configurationElement
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
public void parseStatementNode() {
//这里省略了部分非必要代码逻辑
// 这里是生成sqlSource对象 ,这是sql的核心
// sqlSource 的实现子类有DynamicSqlSource/staticSqlSource/RawSqlSource/ProviderSqlSource
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
// 省略非必要代码
// 生成 MappedStatement 并加入configuration
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
二、注册
调用链如下:
1、confirguration.addMapper()
2、MapperRegistry.addMapper()
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
//new 一个工厂类放到map里
knownMappers.put(type, new MapperProxyFactory<T>(type));
//
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
三、获取
调用链如下:
1、SqlSession.getMapper()
2、configuration.<T>getMapper(type, this);
3、mapperRegistry.getMapper(type, sqlSession);
4、mapperProxyFactory.newInstance(sqlSession); // 这就是刚才注册时 ,生成的工厂对象
5、mapperProxy.invoke();// 核心的逻辑
public T newInstance(SqlSession sqlSession) {
//生成mapperProxy, 其实现了InvocationHandler , 是jdk的动态代理
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
//生成代理 , 注意 这里的代理是比较特殊的 , 因为其没有具体实现
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
四、代理执行
MapperProxy.invoke()
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
//如果是object 普通方法,直接调用
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//找到mapperMehtod对象
//这个对象里包装了一个mapper的sql标签
/**
private final SqlCommand command;
private final MethodSignature method;
*/
final MapperMethod mapperMethod = cachedMapperMethod(method);
//执行
return mapperMethod.execute(sqlSession, args);
}
public Object execute(SqlSession sqlSession, Object[] args) {
//已selectOne为例 , 其他代码忽略
Object param = method.convertArgsToSqlCommandParam(args);
//这里是通过sqlSession -> executor 来执行查询的
result = sqlSession.selectOne(command.getName(), param);
}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)