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.