MyBatis源码简单分析
准备工作
Mybatis官网地址:https://blog.mybatis.org/
MyBatis官方文档地址:https://mybatis.org/mybatis-3/
MyBatis源码下载地址:https://mybatis.org/mybatis-3/
可以从Git上面下载MyBatis的源码压缩包,解压之后,通过idea打开这个maven项目,可以使用maven插件compile编译,开始会爆出error,把项目中的license.txt文件删除即可。
导入MySQL驱动依赖
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version>
</dependency>
测试程序是否能运行
public class Test01 {public static void main(String[] args) throws IOException {InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.getUserList();for (User user : userList){System.out.println(user);}}
}
此时对应要创建mapper.xml文件和对应的Mapper接口,并且通过mybatis-config.xml文件绑定。
MyBatis通过四步完成了JDBC的封装。可以从这四个方面切入分析MyBatis源码。
1.获取文件输入流
Resources.getResourceAsStream(“mybatis-config.xml”);
//最终底层调用的是ClassLoaderWrapper对象的,使用加载器对象中的类加载器来获得输入流。
ClassLoader[] getClassLoaders(ClassLoader classLoader) {return new ClassLoader[]{classLoader,//传递的参数为nulldefaultClassLoader,//默认没有赋值nullThread.currentThread().getContextClassLoader(),//通过当前线程获取类加载器对象getClass().getClassLoader(),//通过当前类获取加载器对象systemClassLoader};//初始化ClassLoaderWrapper对象赋值ClassLoader.getSystemClassLoader();
}
//最终是通过ClassLoader对象调用getResourceAsStream方法获取的输入流
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {for (ClassLoader cl : classLoader) {if (null != cl) {InputStream returnValue = cl.getResourceAsStream(resource);if (null == returnValue) {returnValue = cl.getResourceAsStream("/" + resource);}if (null != returnValue) {return returnValue;}}}return null;
}
2.构建DefaultSqlSessionFactory对象
new SqlSessionFactoryBuilder().build(inputStream);
//enviroment为null,properties为null
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {try {XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);//在XMLConfigBuilderreturn build(parser.parse());} catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);} finally {ErrorContext.instance().reset();try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {// Intentionally ignore. Prefer previous error.}}
}
//创建XMLConfigBuilder对象之前调用重载的构造方法先创建XMLMapperEntityResolver对象,此时的enviroment和props还是为null
//XMLMapperEntiryRresolver对象是为了识别mybatis-config.xml以及mapper.xml文件里面的内容
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
//再创建XPathParser,依次参数inputStream,true,null,entityResolver
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {commonConstructor(validation, variables, entityResolver);//给XPathParser对象属性赋值//validation,entityResolver,variables为null,xpath//http://java.sun.com/jaxp/xpath/dom,xpath传教用到的urithis.document = createDocument(new InputSource(inputStream));//给document对象赋值,
}
1、commonConstructor方法给XPathParser属性赋值;
//XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri);
//通过debug发现,会先进入InstrumentationImpl类,再将XPahtFactoryFinder先进行类加载,初始化类里面的静态变量,然后再进行new对象执行,在执行下面方法过程中,会读取java.home/lib/jaxp.properties路径下是否有这个文件。最终通过反射创建的XPathFactoryImpl实例。
XPathFactory f = _newFactory(uri);//底层最终用到的是反射创建对象
assert xpathFactory == null;//使用到了没有用到的修饰符,断言,如果xpathFactory不为null就抛出异常
xPathFactory = (XPathFactory) clazz.newInstance();
//最终通过反射创建XPathFactory类型的对象,实际创建的是XPathFactoryImpl对象
Xpath xpath = new XpathImpl(null,null,false,true,new FeatureManager());2、createDocument(new InputSource(inputStream))给XPathParser的document属性赋值Document类型;
//factory = DocumentBuilderFactory.newInstance();最终通过是DocumentBuilderFactory.class.newInstance()构造实例
//上面实例中的属性:Map<String, Object> attributes,Map<String, Boolean> features均为null。
//1.factory.setFeature("http://javax.xml.XMLConstants/feature/secure-processing",true);features=new HashMap;
往features的String,Boolean集合中添加了一个键值对;
//2.factory.setValidating(validation)给DocumentBuilderFactory属性validation赋值true;原来是false
//3.factory.setNamespaceAware(false);给DocumentBuilderFactory属性namespaceAware赋值false;原来是false;
//4.factory.setIgnoringComments(true);给DocumentBuilderFactory属性namespaceAware赋值ignoreComments赋值true;f
//5.factory.setIgnoringElementContentWhitespace(false);DocumentBuilderFactory属性whitespace赋值false;false
//6.factory.setCoalescing(false);DocumentBuilderFactory属性coalescing赋值false;原来值为false
//7.factory.setExpandEntityReferences(true);DocumentBuilderFactory属性expandEntityRef属性为true;原来值f
validating验证;namespaceAware命名空间感知;whitespace空白;expandEntityRef展开实体引用;ignoreComments忽略注释;coalescing凝聚;上面的set开头的方法完成factory实例属性的部分初始化;
//DocumentBuilder builder= factory.newDocumentBuilder();new DocumentBuilderImpl(factory,null,features,true);DocumentBuilderImpl构造方法执行domParser = new DOMParser();//无参构造调用this(null,null),调用super(new XIncludeAwareParserConfiguration())给父类XMLParser的属性fConfiguration赋值,并且初始化部分参数。fConfiguration = new XIncludeAwareParserConfiguration();
DOMParser extends AbstractDOMParser extends AbstractXMLDocumentParser extends XMLParser;XIncludeAwareParserConfiguration实例初始化;new XIncludeAwareParserConfiguration()调用this(null,null,null)调用super(null,null,null)再调用super(null);
ParserConfigurationSettings(null){Set<String> fRecognizedFeatures = new HashSet<String>();Set<String> fRecognizedProperties = new HashSet<String>();Map<String, Boolean> fFeatures = new HashMap<String, Boolean>();Map<String, Object> fProperties = new HashMap<String, Object>();XMLComponentManager fParentSettings = null;Map<String,Boolean> fFeatures = new HashMap();//由XML11Configuration再次赋值Map<String, Object> fProperties = = new HashMap();//由XML11Configuration再次赋值
}XML11Configuration(null,null,null){ArrayList fComponents = new ArrayList();ArrayList fXML11Components = new ArrayList();ArrayList fCommonComponents = new ArrayList();Map<String, Object> fProperties = = new HashMap();//fEntityManager实例处理XMLEntityManager fEntityManager = new XMLEntityManager();//XMLEntityManager在实例化的过程中,也初始化了部分属性,用到的属性有XMLEntityScanner fEntityScanner = new XMLEntityScanner();String[] recognizedFeatures的数组元素添加至fRecognizedFeatures集合中;fFeatures集合中put进去键值对;String[] recognizedProperties;//fRecognizedProperties.addAll(Arrays.asList(数组));SymbolTable fSymbolTable = symbolTable == null ? new SymbolTable() : symbolTable;//fProperties.put("http://apache.org/xml/properties/internal/symbol-table", fSymbolTable);fProperties.put("http://apache.org/xml/properties/internal/entity-manager", fEntityManager);fCommonComponents.add(component);//componnet:fEntityManager、
//上面方法执行中从component中取的一些常量,如果这些至不在fRecognizedFeatures、fRecognizedProperties属性中,添加进去
//fFeatures、fProperties添加没有加入的元素,如果有添加进去一次,则fConfigUpdated改为true
//这两者中fFeatures不含ALLOW_JAVA_ENCODINGS T,WARN_ON_DUPLICATE_ENTITYDEF T,STANDARD_URI_CONFORMANT F
//fProperties不含BUFFER_SIZE=new Integer(DEFAULT_BUFFER_SIZE);//XMLErrorReporter实例处理XMLErrorReporter fErrorReporter = new XMLErrorReporter();//初始化属性Map<String, MessageFormatter> fMessageFormatters = new HashMap<>();//XMLLocator fLocator = fentityManager.entityScanner;get了属性fProperties.put("http://apache.org/xml/properties/internal/error-reporter", fErrorReporter);fCommonComponents.add(component);//component:fErrorReporter
//fErrorReporter获取的属性都有,许需要添加属性进去//XMLNSDocumentScannerImpl实例处理XMLNSDocumentScannerImpl fNamespaceScanner = new XMLNSDocumentScannerImpl();fProperties.put("http://apache.org/xml/properties/internal/document-scanner", fNamespaceScanner);addComponent((XMLComponent) fNamespaceScanner);
XMLNSDocumentScannerImpl extends XMLDocumentScannerImpl extends XMLDocumentFragmentScannerImpl extends XMLScanner
//fComponents.add(component);component:fNamespaceScanner;
//addRecognizedParamsAndSetDefaults(component);component:fNamespaceScanner;
//在XMLDocumentScannerImpl的数组RECOGNIZED_FEATURES和XMLDocumentFragmentScannerImpl中的数组RECOGNIZED_FEATURES进行了拼接。RECOGNIZED_PROPERTIES、RECOGNIZED_PROPERTIES数组拼接。//这里和上面唯一不同的是,下面使用了数组的拼接。
//如果fRecognizedFeatures、fRecognizedProperties不含数组中的元素,之间添加至各自的Set集合中。//1.先将对象put进去fProperties的<String,Object>的map集合中//2.fComponents的list集合有没有,没有add进去//3.fRecognizedFeatures和fRecognizedProperties的set集合有没有每个特点对象里面的常量,没有就add进去。//4.fFeatures<String,Boolean>和fProperties<String,Object>的map集合有没有这些元素,没有就add进去//往fProperites中put了两队键值对//fErrorReporter的map<String,MessageFormatter>中put了两队键值对//最后获取本地Locale,并且设置在XIncludeAwareParserConfiguration实例和fErrorReporter实例的locale属性。fConfigUpdated = false;
}
XIncludeAwareParserConfiguration(null,null,null){//前面往fComponents、fXML11Components、fXML11Components里面的对象都调用了设置属性的方法NamespaceSupport fNonXIncludeNSContext = new NamespaceSupport();NamespaceContext fCurrentNSContext = fNonXIncludeNSContext;setProperty(NAMESPACE_CONTEXT, fNonXIncludeNSContext);//最后会将键值对添加至fProperties.put(propertyId, value)中
}
到这里,XIncludeAwareParserConfiguration对象创建完毕;
XIncludeAwareParserConfiguration extends XML11Configuration extends ParserConfigurationSettings;DOMParser实例初始化;
XMLParser(new XIncludeAwareParserConfiguration()){fConfiguration = config;fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);
{http://apache.org/xml/properties/internal/entity-resolver,http://apache.org/xml/properties/internal/error-handler}
}
AbstractXMLDocumentParser(new XIncludeAwareParserConfiguration()){XMLDocumentHandler fDocumentHandler = new DOMParser();//XIncludeAwareParserConfiguration实例属性赋值XMLDTDHandler fDTDHandler = new DOMParser();XMLDTDContentModelHandler fDTDContentModelHandler = new DOMParser();
}
AbstractDOMParser(new XIncludeAwareParserConfiguration()){fConfiguration.addRecognizedFeatures (RECOGNIZED_FEATURES);String[] RECOGNIZED_FEATURES = {http://xml.org/sax/features/namespaces,http://apache.org/xml/features/dom/create-entity-ref-nodes,http://apache.org/xml/features/include-comments,http://apache.org/xml/features/create-cdata-nodes,http://apache.org/xml/features/dom/include-ignorable-whitespace,http://apache.org/xml/features/dom/defer-node-expansion};往fComponents、fXML11Components、fXML11Components对象里面的设置布尔值;fConfiguration.addRecognizedProperties (RECOGNIZED_PROPERTIES);String[] RECOGNIZED_PROPERTIES = {http://apache.org/xml/properties/dom/document-class-name,http://apache.org/xml/properties/dom/current-element-node};fConfiguration.setProperty (DOCUMENT_CLASS_NAME,DEFAULT_DOCUMENT_CLASS_NAME);//两个都是String类型//className,com.sun.org.apache.xerces.internal.dom.DocumentImpl
}
DOMParser(null,null){super(new XIncludeAwareParserConfiguration());fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);fConfiguration.addRecognizedFeatures(RECOGNIZED_FEATURES);//还是往这个set集合里面添加没有的元素
}DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs,Map<String, Boolean> features, boolean secureProcessing);
DocumentBuilderImpl(this,null,features,true)//freatures现在只有一对键值对{http://javax.xml.XMLConstants/feature/secure-processing=true//1.先初始化了DOMParser实例ErrorHandler fInitErrorHandler = new DefaultValidationErrorHandler(domParser.getXMLParserConfiguration().getLocale());Locale.getDefault();//获取的Locale和这个实例初始化一样都是获取Locale.getDefault()setErrorHandler(fInitErrorHandler);//最终是给fConfiguration中的三个对象集合中对应的对象设置属性domParser.setFeature(http://xml.org/sax/features/validation,true);domParser.setFeature(http://xml.org/sax/features/namespaces,true);domParser.setFeature(http://apache.org/xml/features/dom/include-ignorable-whitespace,true);domParser.setFeature(http://apache.org/xml/features/dom/create-entity-ref-nodes,false);domParser.setFeature(http://apache.org/xml/features/include-comments,false);domParser.setFeature(http://apache.org/xml/features/create-cdata-nodes,true);fSecurityPropertyMgr = new XMLSecurityPropertyManager();domParser.setProperty(http://www.oracle.org/xml/jaxp/properties/xmlSecurityPropertyManager, fSecurityPropertyMgr);//domParser属性securityPropertyManager赋值,然后三大对象集合中对象属性赋值,最终添加到fProperties<String,Object>map集合中。fSecurityManager = new XMLSecurityManager(secureProcessing);//true//domParser属性securityManager赋值domParser.setProperty(SECURITY_MANAGER, fSecurityManager);Schema grammar = null;fSchemaValidationManager = null;fUnparsedEntityHandler = null;fSchemaValidatorComponentManager = null;fSchemaValidator = null;setFeatures(features);//最终将键值对添加至fFeatures中setDocumentBuilderFactoryAttributes(dbfAttrs);//dbfAttrs = nullEntityResolver fInitEntityResolver = domParser.getEntityResolver();//fConfiguration中没有这个键值对
}
DocumentBuilderImpl实例初始化完成,在这个过程中,先完成XIncludeAwareParserConfiguration实例初始化,赋值给DOMParser的属性fConfiguration,再初始化完成DOMParser实例,再DocumentBuilderImpl构造方法中完成属性的赋值;builder.setEntityResolver(entityResolver);//new XMLMapperEntityResolver()
fConfiguration.setProperty(ENTITY_RESOLVER,new EntityResolverWrapper(entityResolver));
//http://apache.org/xml/properties/internal/entity-resolver=obj,put进fProperties<String,Object>集合。
builder.setErrorHandler(errorHandler);
//http://apache.org/xml/properties/internal/error-handler=obj。中从fConfiguration对象中拿ErrorHandlerWrapper实例,存在实例,给实例的属性ErrorHandler fErrorHandler赋值errorHandler,如果不存在,创建一个ErrorHandlerWrapper实例并且设置上面同样的属性。
domParser.parse(is);//new InputSource(inputStream),inputStream是mybatis配置文件流
//XMLInputSource xmlInputSource = new XMLInputSource(null,null,null);
//xmlInputSource.setByteStream(inputSource.getByteStream());inputStream
//xmlInputSource.setCharacterStream(inputSource.getCharacterStream());null
//xmlInputSource.setEncoding(inputSource.getEncoding());null
parse(xmlInputSource);new XMLInputSource(null,null,null);方法重载
//securityManager、securityPropertyManager属性都已经赋值,不为null。
fConfiguration.parse(inputSource);//XML11Configuration,用fParseInProgress标志控制
//setInputSource(source);source = new XMLInputSource(null,null,null);finputSource
parse(true);
//fValidationManager.reset();将ValidationManager对象的Vector集合执行removeAllElements(),两个属性赋值false
//fVersionDetector.reset(this);将fConfiguration对象的fSymbolTable、fErrorReporter、fEntityManager从map集合中取出来赋值给XMLVersionDetector的三个对应属性,也是属性初始化过程。
//configurePipeline();初始化fCurrentScanner实例,XMLDocumentScannerImpl
//resetCommon();将fCommonComponents集合里面的对象调用reset(XMLComponentManager componentManager)
short version = fVersionDetector.determineDocVersion(fInputSource);//version = 1;
//xml流read()前四次{60,63,120,109},Object[] encodingDesc = new Object{"UTF-8",null}
//RewindableInputStream实例的reset方法,UTF8Reader reader
//fCurrentEntity对象初始化,
fInputSource = null;//最终属性赋值为null
Document doc = domParser.getDocument();
//发现直接是从domParser实例的父类属性中fDocument中get值,这个值初始化只能的父类的startDocument方法,查找对象创建过程中哪里调用了这个方法。经过之前的总结发现是在XML11Configuration startDocumentParsing中初始化了document对象,查找到发现不对。通过debug测试看能否找到调用fDocument方法,通过debug发现就是configuration对象调用parse(true)方法fVersionDetector.startDocumentParsing((XMLEntityHandler) fCurrentScanner, version)时完成了document对象的初始化。
domParser.dropDocumentReferences();
//将里面的属性赋值为null
代码到这里标志XPathParser对象创建完毕,开始创建XMLConfigBuilder对象。parser是XMLConfigBuilder实例
parser.parse();
Configuration parse(){parseConfiguration(parser.evalNode("/configuration"));return configuration;
}
//Configuration对象的属性parser是XPathParser类型
XPathParser{XNode evalNode(String expression);//调用evalNode(document,var1)XNode evalNode(Object root,String expression);Object evalNode(var2,var1,QName);//调用XPathImpl xpath的evalNode方法
}
XPathImpl{Object evalNode(String expression,Object item,QName returnType);XObject eval(expression,item);
}通过debug获取的截取获取的evaluate(String expression, Object root, QName returnType)返回值为null;
关键代码{XPathImp{XObject resultObject = eval(expression, item);"/configuration",DeferredDocumentImpl对象;com.sun.org.apache.xpath.internal.XPath xpath = new XPath(expression,null,prefixResolver,0);
//m_funcTable = new FunctionTable();初始化了m_funcTable的Class数组和map集合
//errorListener = new com.sun.org.apache.xml.internal.utils.DefaultErrorHandler();
//m_pw = new PrintWriter(System.err, true);
//m_patternString = expression;
//new com.sun.org.apache.xpath.internal.compiler.XPathParser(errorListener,null);
//Compiler compiler = new Compiler(errorListener, locator, m_funcTable);
//Expression expr = WalkingIteratorxpathSupport = new com.sun.org.apache.xpath.internal.XPathContext();NodeIterator ni = new com.sun.org.apache.xml.internal.dtm.ref.DTMNodeIterator(XNodeSet)}XPath{xobj = m_mainExp.execute(xctxt);//m_mainExp = WalkingIterator//XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance());getInstance就是m_mainExp//iter.setRoot(xctxt.getCurrentNode(), xctxt);//XNodeSet 中属性DTMIterator m_iter m_mainExp}
}
只要debug进入XPathImpl的ni.nextNode()的方法,返回结果为null。只能跳过handle取值过程。
DTMNodeIterator{public Node nextNode() throws DOMException{if(!valid)throw new DTMDOMException(DOMException.INVALID_STATE_ERR);int handle=dtm_iter.nextNode();//dtm_iter XNodeSet,这里的handle肯定不是-1if (handle==DTM.NULL)return null;return dtm_iter.getDTM(handle).getNode(handle);}
}//XIncludeAwareParserConfiguration
//XML11Configuration startDocumentParsing((XMLEntityHandler) fCurrentScanner, version);初始化document对象
//XMLDTDValidator实现XMLDocumentHandler
//XPathParser中的document实际是new DeferredDocumentImpl(false)的父类实现了Document接口,接口继承Node接口,在初始化document对象时,都向上super调用了父抽象类的构造方法。
DeferredDocumentImpl extends DocumentImpl extends CoreDocumentImpl extends ParentNode extendss ChildNode extends NodeImpl implents Document
//WalkingIterator extends LocPathIterator
//1.new DeferredDocumentImpl(false);super(false) => new DocumentImpl(false);super(false)
//2.new CoreDocumentImpl(false);super(null) => protected ParentNode(CoreDocumentImpl ownerDocument);super(null);this.ownerDocument = null;CoreDocumentImpl ownerDocument属性在PatentNode抽象类中
//3.protected ChildNode(CoreDocumentImpl ownerDocument);super(null) => protected NodeImpl(CoreDocumentImpl ownerDocument)NodeImpl ownerNode = null;
//在初始化ParentNode抽象类CoreDocumentImpl类型ownerDocument时,赋值为空,而后在子类CoreDocumentImpl构造方法中赋值为this。
//XNode中的Node node是DeferredElementImpl实例对象
//DeferredElementImpl只有一个构造方法,参数DeferredDocumentImpl ownerDoc, int nodeIndex,ownerDoc应该传入了初始化的DeferredDocumentImpl实例,nodeIndex环境的是4。构造方法执行的类
DeferredElementImpl extends ElementImpl extends ParentNode extends ChildNode>NodeImpl在创建Environment对象时,使用了一种方式,通过先创建Environment的静态内部类Builder,这个内部类的属性和外部类属性完全相同,通过先对这个对象赋值,再通过内部类对象的方法创建外部类的对象。最终将environment对象注入到config中//BeanWrapper implements ObjectWrapper
//Reflector setMethods属性JDBC=JdbcTransactionFactory.class
MANAGED=ManagedTransactionFactoryJNDI=JndiDataSourceFactory
POOLED=PooledDataSourceFactory PooledDataSourceFactoty继承了UnpooledDataSourceFactor
UNPOOLED=UnpooledDataSourceFactory
//UnpooledDataSourceFactory拥有PooledDataSource数据源属性
//最终传教SqlSessionFactory接口实现类的对象
public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);
}
mybatis绑定mapper可以通过源码得知package优先级最高,其次是resource或者url或者class
通过SqlSessionFactoryBuilder对象传入的输入流,将解析的xml文件信息放置在Configuration对象中,解析xml文件使用到类,时jdk自带的类,mybatis的类通过封装创建这些类的实例,来调用这些实例的方法完成xml的解析,直接将解析好的Configuration对象调用SqlSessionFactoryBuilder构造方法。
3.创建DefaultSqlSession实例
sqlSessionFactory.openSession()
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {//获取environment对象的属性TransactionFactory、DataSource,数据源初始化在创建完成时就完成初始化了。//transactionManager type="JDBC"=JdbcTransactionFactory.class//dataSource type="POOLED"=PooledDataSourceFactory.class,dataSource时PooledDataSourceFactory的属性final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);//JdbcTransaction实例创建tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);//Executor执行器实例创建,默认SimpleExecutorfinal Executor executor = configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}
将configuration、executor、autoCommit三个属性赋值给DefaultSqlSession对象。
4.获取Mapper接口实例
sqlSession.getMapper(UserMapper.class)
sqlSession.getMapper(UserMapper.class);//这里采用了jdk的动态代理模式
动态代理使用到的类MapperRegistry、MapperProxy、MapperProxyFactory
//通过MapperRegistry存储配置文件接口信息,Class<?>, MapperProxyFactory<?>的key,valuemap集合,调用MapperProxyFactory<T>对象的newInstance方法动态代理创建接口对象,在这里是MapperProxy实现InvocationHandler接口,重写了invoke方法。
1.invoke(Object proxy,Method method,Object[] args);
2.cacheInvoker(method).invoke(proxy,method,args,sqlSession);
//MapperMethodInvoker cacheInvoker(Method method)该方法执行过程中,正常情况下Map<Method, MapperMethodInvoker> methodCache集合中会put进去method=MapperProxy.PlainMethodInvoker一对键值对,对象中的属性mapperMethod会有另外两个静态内部类:SQLCommand,MethodSignature
3.mapperMethod.execute(sqlSession, args);
SqlCommandType{UNKNOWN,INSERT,UPDATE,DELETE,SELECT,FLUSH}4.最终通过动态代理,底层最终调用的还是sqlSession对象也就是DefaultSqlSession对象实例。
public <E> List<E> selectList(String statement, Object parameter){};
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds){};
5.使用到JDBC4Connection.prepareStatement(sql)。ResultSetWrapperrang结果集处理
源码可用点
java.io.File.separator;//等价于"\\"
new Properties().load(new FileInputStream(new File(path)));//将properties文件以流的方式读取成Properties实例
assert file == null;//如果file属性不为null,程序出错
Class.forName(className,false,classLoader);//不进行类加载获取Class类,className要带全路径名
clazz.cast(obj);将obj实例类型转换为clazz类型,能转换正常执行,不能则抛出异常;
type instanceof TypeVariable;//不知道这个是什么类型才这样
type instanceof ParameterizedType;//type List<?>,Map<String,Object>
type instanceof GenericArrayType;//type Map<?,?>[],map数组list数组
//类型基本上都是Parameterized
clazz1.isAssignableFrom(clazz2);//clazz2是clazz1的子类或者本身返回true
MyBatis源码简单分析相关推荐
- Hessian 源码简单分析
Hessian 源码简单分析 Hessian 是一个rpc框架, 我们需要先写一个服务端, 然后在客户端远程的调用它即可. 服务端: 服务端通常和spring 做集成. 首先写一个接口: public ...
- poco源码简单分析
自动化工具poco源码简单分析 Airtest简介 Airtest是网易游戏开源的一款UI自动化测试项目,目前处于公开测试阶段,该项目分为AirtestIDE.Airtest.Poco.Testlab ...
- FFmpeg的HEVC解码器源码简单分析:概述
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- FFmpeg的HEVC解码器源码简单分析:解码器主干部分
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- JSP 编译和运行过程与JSP源码简单分析
JSP 编译和运行过程与JSP转移源码简单分析 Web容器处理JSP文件请求的执行过程主要包括以下4个部分: 1. 客户端发出Request请求 2. JSP Container 将JSP转译成Ser ...
- MyBatis源码骨架分析
源码包分析 MyBatis 源码下载地址:https://github.com/MyBatis/MyBatis-3 MyBatis源码导入过程: 下载MyBatis的源码 检查maven的版本,必须是 ...
- 线程的3种实现方式并深入源码简单分析实现原理
前言 本文介绍下线程的3种实现方式并深入源码简单的阐述下原理 三种实现方式 Thread Runnable Callable&Future 深入源码简单刨析 Thread Thread类实现了 ...
- reentrantlock失效了?_ReentrantLock 源码简单分析
JAVA中锁的实现最常见的方式有两种,一种是 synchronized关键字,一种是Lock.实际的开发过程中,要对这两种方式进行取舍. synchronized是基于JVM层面实现的, Lock却是 ...
- ChaLearn Gesture Challenge_3:Approximated gradients源码简单分析
前言 上一篇博文ChaLearn Gesture Challenge_2:examples体验 中简单介绍了CGC官网提供的丰富的sample,本节来简单分下其中的一个sample源码,该sample ...
最新文章
- Asp.net SignalR 实现服务端消息推送到Web端
- 乘法逆元总结 3种基本方法
- Elasticsearch中的Multi Match Query
- 在线普通话转粤语发音_香港最新悬疑侦探剧福尔摩师奶,粤语知识好难
- uboot烧录到SD卡
- centos 需要哪些常用端口_仓库加盟:电商仓库需要配备哪些常用仓储设备
- 用纯css改变下拉列表select框的默认样式
- android 黑名单中电话拦截
- matlab2017a安装出现license checkout failed Error-8
- 一二线城市知名IT互联网公司名单!
- 机器学习读书笔记: 概率图模型
- 联合查询(多表查询)
- Java调用WebService接口实现发送手机短信验证码功能,java 手机验证码,WebService接口调用
- [转]验证码识别技术
- kubernetes device or resource busy的问题
- HearthBuddy炉石兄弟 格雷迈恩
- 连接局域网内的Mysql8服务器
- SDN南向接口和北向接口区别
- 微信公众号开发,移动端开发遇到的问题及其他技巧
- Asp.net 路由详解
热门文章
- 折半查找判定树 二叉排序树 查找成功平均查找长度 查找失败平均查找长度
- 如何生成tfrecord
- 农村商业银行服务器未收到证书,不及时更新“证书” 当心网银U盾失效
- DiskMan使用方法
- Excel保护怎么解除保护
- mysql中的表自增的id太大了,可以重新设置自增起始值
- 探寻软件的永恒之道 ——评介《建筑的永恒之道》 - 撰文/透明
- SourceTree安装跳过注册
- html.append清空,关于jquery的append()和html()使用
- 地图上如何量方位角_地图投影怎么做到按条件(等角、等面积、等距)投影的?...