Resource Loading via ClassLoader
The process begins with loading the configuration file, typically mybatis.xml, using Resources.getResourceAsStream(). This method leverages Java’s class loading mechanism to locate resources within the classpath. It does not resolve absolute file paths directly but instead relies on the ClassLoader hierarchy to find the resource.
Internally, Resources.getResourceAsStream() delegates to ClassLoader.getResourceAsStream(). The class loader chain includes:
- The current thread’s context class loader
- The class loader associated with the calling class
- The system class loader (typically
URLClassLoader) - A fallback to the parent class loader
The actual lookup occurs through findResource() in URLClassLoader, which uses a URLClassPath instance to search for the resource among JARs and directories in the classpath. If found, it returns an InputStream for reading the configuration.
Configuration Parsing with XMLConfigBuilder
After obtaining the input stream, SqlSessionFactoryBuilder.build(inputStream) is invoked. This triggers the creation of an XMLConfigBuilder instance, responsible for parsing the XML configuration into a Configuration object.
The XMLConfigBuilder constructor initializes a XPathParser to parse the document using XPath expressions. It then calls parse() to begin processing the root <configuration> element. Inside parseConfiguration(), various sections are processed sequentially:
- Properties
- Settings
- Type aliases
- Plugins
- Object factories
- Transaction managers and data sources
- Mappers
Each section is parsed using evalNode() and corresponding handler methods, populating the Configuration object with metadata needed for runtime execution.
SqlSessionFactory Initialization
Once the Configuration is fully constructed, build(Configuration) returns a DefaultSqlSessionFactory. This factory is immutable and serves as the entry point for creating SqlSession instances.
SqlSession Creation and Executor Instantiation
When sqlSessionFactory.openSession() is called, the system:
- Retrieves the active environment from
Configuration - Creates a
TransactionFactorybased on the environment settings - Initializes a
Transactionobject using the data source and isolation level - Constructs an
Executorbased on the configured type (SIMPLE,REUSE, orBATCH) - Wraps the executor with caching and plugin interceptors
- Returns a new
DefaultSqlSessioninstance
The Executor is central to SQL execution. Depending on the type:
SimpleExecutor: Creates a newStatementper executionReuseExecutor: Reuses prepared statementsBatchExecutor: Enables batch operations
Caching is added if enabled via CachingExecutor, and all components are enhanced via the interceptor chain (pluginAll).
StatementHandler and SQL Preparation
For each database operation, a StatementHandler is created through RoutingStatementHandler, which routes to the appropriate implementation (PreparedStatementHandler, CallableStatementHandler, etc.).
The prepare() method in PreparedStatementHandler:
- Precompiles the SQL using
instantiateStatement() - Sets timeout and fetch size options
- Returns the prepared statement
Then, parameterize() is called to bind parameters using ParameterHandler, which:
- Extracts values from the parameter object
- Uses
TypeHandlerto convert types safely - Applies JDBC type mappings
Result Handling and Interceptor Chain
After execution, results are handled by ResultSetHandler, which maps rows to objects based on result maps defined in XML.
Throughout this flow, the InterceptorChain applies user-defined plugins via pluginAll(), wrapping each component in proxy layers for interception before final use.
Mapper Interface Proxying
When sqlSession.getMapper(StudentDao.class) is called, MyBatis creates a dynamic proxy via MapperProxyFactory. The proxy implements InvocationHandler and maintains a cache (methodCache) mapping interface methods to MapperMethod instances.
On method invocation:
MapperProxy.invoke()checks if it's a default method orObjectmethod- Otherwise, it retrieves the cached
MapperMethod - Calls
execute()on that method, which dispatches to the correctSqlSessionoperation (selectOne,insert, etc.)
The MapperMethod interprets method signatures, converts arguments, and selects the right execution path based on return type (e.g., List, Map, Optional, Cursor). For queries, it invokes sqlSession.selectList() or similar.
This entire flow enables a clean separation: developers write plain Java interfaces, and MyBatis dynamically binds them to SQL through reflection, proxies, and metadata-driven execution.