Basic Introduction
MyBatis uses the following design patterns:
- Builder Pattern: SqlSessionFactoryBuilder, Environment
- Factory Method Pattern: SqlSessionFactory, TransactionFactory, LogFactory
- Singleton Pattern: ErrorContext, LogFactory
- Proxy Pattern: MapperProxy, ConnectionLogger
- Composite Pattern: SqlNode, ChooseSqlNode
- Template Method Pattern: BaseExecutor, SimpleExecutor
- Adapter Pattern: Log
- Decorator Pattern: Cache
- Iterator Pattern: PropertyTokenizer
Builder Pattern
Concept Introduction
This pattern separates the construction of a complex object from its representation, allowing the same construction process to create different representations. It belongs to the creational pattern category. Generally, if the construction of an object is too complex to be covered by a constructor, you can use the factory pattern and Builder pattern.
Simply put, it means building complex objects step by step through simple objects.
Simple Example
For example, to assemble a computer, we need: main unit, monitor, keyboard, mouse, speakers.
Write Code
WzkComputer
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WzkComputer {
private String displayer;
private String mouse;
private String keyword;
private String sound;
}
WzkComputerBuilder
public class WzkComputerBuilder {
private WzkComputer wzkComputer = new WzkComputer();
public WzkComputerBuilder installDisplay(String displayName) {
wzkComputer.setDisplayer(displayName);
return this;
}
public WzkComputerBuilder installMouse(String mouseName) {
wzkComputer.setMouse(mouseName);
return this;
}
public WzkComputerBuilder installKeyboard(String keyboardName) {
wzkComputer.setKeyword(keyboardName);
return this;
}
public WzkComputerBuilder installSound(String soundName) {
wzkComputer.setSound(soundName);
return this;
}
public WzkComputer build() {
return wzkComputer;
}
}
WzkBuilderTest
public class WzkBuilderTest {
public static void main(String[] args) {
WzkComputer wzkComputer = new WzkComputerBuilder()
.installDisplay("Samsung")
.installMouse("Logitech")
.installKeyboard("Logitech")
.installSound("Broken Horn")
.build();
System.out.println(wzkComputer);
}
}
Test Run
WzkComputer(displayer=Samsung, mouse=Logitech, keyword=Logitech, sound=Broken Horn)
MyBatis Implementation
SqlSessionFactory building process: MyBatis initialization work is very complex, not something that can be done with just one constructor, so the builder pattern is used with a lot of Builders for layered construction. The core object is Configuration, and XMLConfigBuilder is used for construction.
During MyBatis environment initialization, SqlSessionFactoryBuilder calls XMLConfigBuilder to read all MyBatisMapConfig.xml and all mapper.xml files.
private void parseConfiguration(XNode root) {
try {
// Issue #117: Read properties first
// Parse <properties /> tag
propertiesElement(root.evalNode("properties"));
// Parse <settings Properties settings = settingsAsProperties(root.eval /> tag
Node("settings"));
// Load custom VFS implementation class
loadCustomVfs(settings);
// Parse <typeAliases /> tag
typeAliasesElement(root.evalNode("typeAliases"));
// Parse <plugins /> tag
pluginElement(root.evalNode("plugins"));
// Parse <objectFactory /> tag
objectFactoryElement(root.evalNode("objectFactory"));
// Parse <objectWrapperFactory /> tag
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// Parse <reflectorFactory /> tag
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// Set <settings /> to Configuration property
settingsElement(settings);
// Issue #631: Read it after objectFactory and objectWrapperFactory
// Parse <environments /> tag
environmentsElement(root.evalNode("environments"));
// Parse <databaseIdProvider /> tag
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
} catch (Exception e) {
// Handle exceptions
e.printStackTrace();
}
}
Second, when XMLConfigBuilder builds Configuration object, it also calls XMLMapperBuilder to read Mapper files, and XMLMapperBuilder uses XMLStatementBuilder to read and build all SQL statements.
Factory Pattern
Concept Introduction
In MyBatis, for example, SqlSessionFactory uses the factory pattern. This factory doesn’t have that complex logic; it’s a simple factory pattern.
Simple Factory Pattern: Also known as Static Factory Method pattern, it belongs to the creational pattern. In a simple factory pattern, different class instances can be returned based on different parameters, and the created instances usually have a common parent class.
Simple Example
Suppose there is a computer manufacturer that could previously produce Lenovo computers. With business development, it can now produce HP computers. We can use simple factory to implement this.
Write Code
WzkComputer
public abstract class WzkComputer {
public abstract void start();
}
LenovoComputer
public class LenovoComputer extends WzkComputer {
@Override
public void start() {
System.out.println("Producing Lenovo computer");
}
}
HpComputer
public class HpComputer extends WzkComputer {
@Override
public void start() {
System.out.println("Producing HP computer");
}
}
ComputerFactory
public class ComputerFactory {
public static WzkComputer createComputer(String type) {
switch (type) {
case "lenovo":
return new LenovoComputer();
case "hp":
return new HpComputer();
default:
throw new IllegalArgumentException("Invalid computer type: " + type);
}
}
}
WzkComputerTest
public class WzkComputerTest {
public static void main(String[] args) {
ComputerFactory.createComputer("lenovo").start();
ComputerFactory.createComputer("hp").start();
}
}
MyBatis Implementation
MyBatis uses the factory pattern in the core process of executing SQL statements, obtaining Mappers, and managing transactions - specifically in the creation process of the SqlSession interface.
As you can see, there are many overloaded methods, and DefaultSqlSessionFactory has the default factory implementation.