Exploring Nine Design Patterns in MyBatis: Builder, Factory, Singleton, Proxy, Decorator, Adapter, Composite, Template Method, and Iterator
This article examines nine design patterns employed within MyBatis—Builder, Factory, Singleton, Proxy, Decorator, Adapter, Composite, Template Method, and Iterator—detailing their roles, source code examples, and how they facilitate configuration parsing, SQL execution, and caching in the framework.
Builder Pattern
The Builder pattern separates the construction of a complex object from its representation, allowing the same construction process to create different representations. In MyBatis, SqlSessionFactoryBuilder applies this pattern to read the configuration file, parse XML, and build a Configuration object, which is then used to create a SqlSessionFactory .
Typical usage:
// 1. Load configuration file
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2. Build SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 3. Open a session
SqlSession sqlSession = factory.openSession();
// 4. Execute a query
List
list = sqlSession.selectList("com.chen.mapper.UserMapper.selectUserList");
System.out.println("list.size() = " + list.size());
// 5. Close the session
sqlSession.close();During this process, SqlSessionFactoryBuilder delegates to XMLConfigBuilder , which reads mybatis-config.xml and all *Mapper.xml files, constructing the core Configuration object.
Factory Pattern
MyBatis uses a simple factory to create SqlSessionFactory . The factory method abstracts the creation logic, returning different implementations based on parameters. The SqlSessionFactory interface provides many overloaded openSession methods for obtaining SqlSession instances.
Singleton Pattern
The Singleton pattern ensures a class has only one instance and provides a global access point. MyBatis applies this pattern in ErrorContext (thread‑local singleton) and LogFactory (global logging factory).
ErrorContext stores error information per thread using a ThreadLocal instance, while LogFactory supplies a shared logger for the whole framework.
Proxy Pattern
MyBatis heavily relies on the Proxy pattern to implement mapper interfaces. When a mapper method is invoked, the call is delegated to a dynamically generated proxy that executes the corresponding SQL.
The proxy creation flow:
During configuration parsing, configuration.addMappers(...) scans packages and registers each mapper.
MapperRegistry stores a MapperProxyFactory for each mapper in a Map<Class, MapperProxyFactory> knownMappers .
When Configuration.getMapper(...) is called, mapperRegistry.getMapper obtains the factory and creates a proxy instance via mapperProxyFactory.newInstance(sqlSession) .
The generated proxy implements InvocationHandler ; its invoke method ultimately calls sqlSession → Executor → JDBC prepareStatement to run the SQL.
Composite Pattern
The Composite pattern treats individual objects and compositions uniformly. MyBatis uses it to represent dynamic SQL nodes as a tree. Each SqlNode (e.g., TrimSqlNode , IfSqlNode , TextSqlNode ) forms a node in the tree, and the root node recursively applies all children to build the final SQL.
<update id="update" parameterType="org.format.dynamicproxy.mybatis.bean.User">
UPDATE users
<trim prefix="SET" prefixOverrides=",">
<if test="name != null and name != ''">name = #{name}</if>
<if test="age != null and age != ''">, age = #{age}</if>
<if test="birthday != null and birthday != ''">, birthday = #{birthday}</if>
</trim>
where id = ${id}
</update>Template Method Pattern
MyBatis’s BaseExecutor defines the skeleton of SQL execution (the template method) and delegates specific steps to subclasses such as SimpleExecutor , ReuseExecutor , and BatchExecutor . The template method handles common workflow—statement preparation, parameter handling, result processing—while subclasses implement the concrete execution strategy.
Adapter Pattern
MyBatis adapts various logging frameworks (Log4j, SLF4J, java.util.logging, etc.) to a unified Log interface. Each concrete logger (e.g., Log4jImpl ) holds an instance of the underlying framework’s logger and forwards the four log‑level methods defined by MyBatis.
Decorator Pattern
MyBatis’s caching subsystem uses the Decorator pattern. The core Cache interface is implemented by PerpetualCache . Additional decorators (e.g., LoggingCache , LruCache , BlockingCache ) wrap the base cache to add eviction policies, logging, or thread‑safety.
Iterator Pattern
The Iterator pattern provides a way to traverse a container without exposing its internal structure. MyBatis’s PropertyTokenizer implements Iterator to lazily parse property strings, allowing callers to iterate over each token via hasNext() and next() .
Summary
The essence of design patterns is the practical application of polymorphism combined with solid design principles—Single Responsibility, Open/Closed, and Dependency Inversion. Understanding how MyBatis implements these nine patterns helps developers read framework source code more effectively and apply the patterns flexibly in their own projects.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.