Interpretation of analytical Mybatis source - design pattern summary

Although we all know that there are 26 design patterns, but most remain at the conceptual level, the real development rarely encountered, Mybatis source uses a lot of design patterns, read the source code and observe the application of design patterns in them, capable of more in-depth understanding of design patterns.

Mybatis meet at least the following design patterns:

  • Builder mode, e.g. SqlSessionFactoryBuilder, XMLConfigBuilder, XMLMapperBuilder, -
  • XMLStatementBuilder、CacheBuilder;
  • Factory mode, e.g. SqlSessionFactory, ObjectFactory, MapperProxyFactory;
  • Singleton, e.g. ErrorContext and LogFactory;
  • Proxy mode, the core Mybatis achieve, such as MapperProxy, ConnectionLogger, dynamic agency with the jdk; and -
  • executor.loader package used to achieve the effect javassist cglib or delay loading;
  • Combined mode, e.g. SqlNode and each subclass ChooseSqlNode the like;
  • Template Method pattern, such as BaseExecutor and SimpleExecutor, as well as BaseTypeHandler and all sub-categories such as -
  • IntegerTypeHandler;
  • Adapter mode, its interface and adaptation Mybatis e.g. jdbc, log4j Log other logging framework implemented;
  • Decorator pattern, e.g. Cache package medium realize the respective sub-packets cache.decorators decorator;
  • Iterative mode, such as iterative mode PropertyTokenizer;

Then one by one mode of interpretation, first introduced model their knowledge and interpretation in Mybatis in how to apply the model.

1, Builder mode

Pattern is defined Builder "will build a complex representation of the object and its separation, so that the same construction process can create different representations.", Which belongs to the class model to create, in general, if an object is more complex to build, beyond the scope of the constructor can be contained, you can use the factory pattern and Builder mode, output will build the factory model of a complete product, Builder applied to more complex objects, and even build only a part of the product relative.

During initialization Mybatis environment, SqlSessionFactoryBuilder calls XMLConfigBuilder MybatisMapConfig.xml read all the files and all the * Mapper.xml build core objects Configuration objects Mybatis run, and then the Configuration object as a parameter to build a SqlSessionFactory object.

When building where XMLConfigBuilder Configuration object, also called XMLMapperBuilder * Mapper is used to read the file, but XMLMapperBuilder use XMLStatementBuilder to read and build all SQL statements.

In this process, there is a similar feature that can read these files or configuration Builder, and then do a lot of XpathParser resolution, configuration or grammatical parsing, reflecting generating object, the result is stored in the cache and other steps, so much work It can not include a constructor, and thus uses a lot of Builder to solve the model.

For builder concrete classes, methods are mostly * Build begin with, SqlSessionFactoryBuilder such as, for example, a method comprising:

I.e., the factory object SqlSessionFactory constructed according to different input parameters.

2, the factory pattern

In such SqlSessionFactory Mybatis the factory pattern is used, the plant less complex logic, a simple factory pattern.

Simple factory pattern (Simple Factory Pattern): also known as static factory method (Static Factory Method) mode, which belongs to the class creates a schema. In the simple mode, the factory can return an instance of a different class according to different parameters. Simple factory pattern to define a special class to other classes responsible for creating an instance, the instance is created normally have a common parent class.

SqlSession can be considered a core interface Mybatis work, execute SQL statements can be executed through this interface, access Mappers, management affairs. Connection object is similar to connecting MySQL.

We can see, openSession the Factory method overloading a lot, namely support input autoCommit, Executor, Transaction and other parameters to build the core of SqlSession object. In the default factory implementation DefaultSqlSessionFactory's, there is a way we can see how the factory output of a product:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
			boolean autoCommit) {
		Transaction tx = null;
		try {
			final Environment environment = configuration.getEnvironment();
			final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
			tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
			final 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();
		}
	}
复制代码

This is the underlying method openSession a call, the method reads the start configuration corresponding to the configuration environment, and then initializes TransactionFactory obtain a Transaction object, and then obtain a Transaction object through the Executor, and finally through configuration, Executor, whether constructed of three parameters autoCommit SqlSession.

In fact, here you can also see the clues, SqlSession execution, in fact, is entrusted to the corresponding Executor carried out.

For LogFactory, its implementation code:

public final class LogFactory {
	private static Constructor<? extends Log> logConstructor;
 
	private LogFactory() {
		// disable construction
	}
 
	public static Log getLog(Class<?> aClass) {
		return getLog(aClass.getName());
	}
复制代码

There is a special place, a variable is the type of Log Constructor <? Extends Log>, that is to say the plant is not just a product, but has a range of products Log public interface, such as Log4jImpl, Slf4jImpl and many other specific Log.

3, singleton

Singleton (Singleton Pattern): Singleton ensures that only one instance of a certain class, and to instantiate the instance of the entire system and to provide this class is called singleton class that provides global access method.

Important single embodiment has three modes: First, only one instance of a class; second, it must create an instance of its own; it must provide their own three in this example the entire system. Singleton pattern is an object to create schema. Singleton and member list mode or single-mode state.

There are two places in Mybatis use the singleton pattern, and ErrorContext LogFactory, wherein ErrorContext is a single thread range in each embodiment, a recording error information of the execution environment thread, and is supplied to the entire LogFactory Mybatis logs used in the factory for obtaining projects for the configured log object.

Example ErrorContext single implementation code:

public class ErrorContext {
 
	private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<ErrorContext>();
 
	private ErrorContext() {
	}
 
	public static ErrorContext instance() {
		ErrorContext context = LOCAL.get();
		if (context == null) {
			context = new ErrorContext();
			LOCAL.set(context);
		}
		return context;
	}
复制代码

A constructor is private modifier, having a local static instance variables and instance variables of a method of obtaining, in the process of obtaining instance, first determine whether it is empty, if it is first created, and then returns the constructed object.

Here are just a interesting place, LOCAL static ThreadLocal instance variables using a modified, which means that it belongs to the respective data for each thread, and in the instance () method, first get the instance of this thread, if not create the thread unique ErrorContext.

4, proxy mode

Acting mode can be considered Mybatis core model used, it is precisely because this model, we only need to write Mapper.java interfaces need not be implemented by Mybatis background to help us accomplish specific SQL execution.

Proxy mode (Proxy Pattern): one object is to provide an agent, by the control proxy object reference to the original object. The English called proxy mode Proxy or Surrogate, it is an object-structured mode.

Proxy mode contains the following roles:

  • Subject: abstract thematic roles
  • Proxy: Proxy thematic roles
  • RealSubject: true thematic roles

There are two steps, the first one is to create a Proxy in advance, the second is the use of the time will be automatically requested Proxy, and then to perform a specific business by Proxy;

When we use the Configuration getMapper method calls mapperRegistry.getMapper method, and the method will call mapperProxyFactory.newInstance (sqlSession) to generate a specific agent:

/**
 * @author Lasse Voss
 */
public class MapperProxyFactory<T> {
 
	private final Class<T> mapperInterface;
	private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
 
	public MapperProxyFactory(Class<T> mapperInterface) {
		this.mapperInterface = mapperInterface;
	}
 
	public Class<T> getMapperInterface() {
		return mapperInterface;
	}
 
	public Map<Method, MapperMethod> getMethodCache() {
		return methodCache;
	}
 
	@SuppressWarnings("unchecked")
	protected T newInstance(MapperProxy<T> mapperProxy) {
		return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface },
				mapperProxy);
	}
 
	public T newInstance(SqlSession sqlSession) {
		final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
		return newInstance(mapperProxy);
	}
 
}
复制代码

Here, the object is to get a MapperProxy by T newInstance (SqlSession sqlSession) method, and then calls the T newInstance (MapperProxy mapperProxy) generate the proxy object and returns.

The view MapperProxy code, you can see the following:

public class MapperProxy<T> implements InvocationHandler, Serializable {
 
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		try {
			if (Object.class.equals(method.getDeclaringClass())) {
				return method.invoke(this, args);
			} else if (isDefaultMethod(method)) {
				return invokeDefaultMethod(proxy, method, args);
			}
		} catch (Throwable t) {
			throw ExceptionUtil.unwrapThrowable(t);
		}
		final MapperMethod mapperMethod = cachedMapperMethod(method);
		return mapperMethod.execute(sqlSession, args);
	}
复制代码

Very typically, the MapperProxy InvocationHandler class implements interfaces, and implements the interface to invoke a method.

In this way, we only need to write Mapper.java interface class, when the real implementation of a Mapper interface will be forwarded to MapperProxy.invoke method, and the method is called subsequent sqlSession.cud> executor.execute> prepareStatement and a series of methods to complete the SQL execution and return.

5, combined mode

Combination pattern combining a plurality of objects form a tree structure to represent - hierarchy of "integral part" of.

Combination patterns consistent individual objects (objects leaf), and composite objects (objects in combination), it objects into a tree structure, it can be used to describe the relationship with the whole portion. It also blur the simple elements (leaf objects) and the concept of complex elements (container object), so that customers can process the image element as easy to handle complex elements, so that the client can be decoupled from the internal structure of the complex elements.

In combination mode also need to note that the most critical areas combined mode: leaf objects and combinations of objects that implement the same interface. This is combined mode can be leaf nodes and target nodes reasons consistent treatment.

Mybatis support the power of dynamic SQL, such as the following 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>
复制代码

In use there to trim, if the dynamic elements, etc., may be generated according to the SQL condition under different circumstances;

In DynamicSqlSource.getBoundSql method, the call rootSqlNode.apply (context) method, apply methods are all dynamic nodes Implemented Interfaces:

public interface SqlNode {
	boolean apply(DynamicContext context);
}
复制代码

For achieving this SqlSource interface all nodes, each node is a combination of the whole pattern tree:

Simple combination of the patterns is that all the nodes are child nodes of the same class may be recursively performed down, such as for TextSqlNode, because it is the bottom of the leaf node, so the corresponding content directly to append to the SQL statement:

	@Override
	public boolean apply(DynamicContext context) {
		GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
		context.appendSql(parser.parse(text));
		return true;
	}
复制代码

But for IfSqlNode, we need to do first judgment, if it is judged by, still calls the child element SqlNode, namely contents.apply way to achieve resolve recursive.

@Override
	public boolean apply(DynamicContext context) {
		if (evaluator.evaluateBoolean(test, context.getBindings())) {
			contents.apply(context);
			return true;
		}
		return false;
	}
复制代码

6, the template method pattern

Template Method pattern is one of the most common of all modes several modes, the basic technology is based on inheritance reuse code.

Template Method pattern need to develop cooperation between the abstract and concrete subclasses designer. A designer responsible for a given contour and skeleton algorithm, others give designers are responsible for the individual logical steps of the algorithm. These methods represent specific logical steps of a method called basic (primitive method); but these methods are collectively basic method is called template method (template method), the name of this design pattern is to come from.

Template class defines a skeleton of the algorithm operation, some steps to subclasses delay. Subclasses that may not change the structure of certain steps of an algorithm of the algorithm to redefine.

In Mybatis in, sqlSession SQL execution, are entrusted to the Executor implementation, Executor contains the following structure:

Which BaseExecutor on the use of a template method pattern, which implements most of the SQL execution logic, then the following method to subclass customized complete:

protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
 
	protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException;
 
	protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
			ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
复制代码

The Template Method class has achieved several concrete subclasses, using different strategies:

  • Simple SimpleExecutor: Each time update or select, just open a Statement object, run out immediately closed Statement object. (Statement may be PrepareStatement or objects)
  • Reuse ReuseExecutor: execute update or select, as a key to find sql Statement object exists on the use, it does not exist to create, after use, do not close the Statement object, but placed Map <String, Statement> inside for the next time you use . (Statement may be PrepareStatement or objects)
  • Batch BatchExecutor: execute update (not select, JDBC does not support batch select), all sql are added to the batch (addBatch ()), waiting for the uniform implementation (executeBatch ()), it caches multiple Statement objects, each a Statement objects are addBatch () after completion, waiting for execution one by one executeBatch () batch; BatchExecutor equivalent to maintaining a plurality of buckets, each bucket have installed SQL lot of their own, like apples and blue and filled the many apples, tomatoes and blue and filled a lot of tomatoes, finally, and then poured into a unified warehouse. (Statement may be PrepareStatement or objects)

For example achieved in the update method SimpleExecutor:

	@Override
	public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
		Statement stmt = null;
		try {
			Configuration configuration = ms.getConfiguration();
			StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null,
					null);
			stmt = prepareStatement(handler, ms.getStatementLog());
			return handler.update(stmt);
		} finally {
			closeStatement(stmt);
		}
	}
复制代码

7, the adapter mode

Adapter mode (Adapter Pattern): a client interface into another interface desired, so that the class interface adapter mode may be incompatible with the work, which alias wrapper (Wrapper). Adapter mode either as structural model type, may be used as the object structure schema.

In Mybatsi the logging package, there is a Log Interface:

/**
 * @author Clinton Begin
 */
public interface Log {
 
	boolean isDebugEnabled();
 
	boolean isTraceEnabled();
 
	void error(String s, Throwable e);
 
	void error(String s);
 
	void debug(String s);
 
	void trace(String s);
 
	void warn(String s);
 
}
复制代码

This interface defines the log method Mybatis direct use, and the interface specific implementation Log Who does? Mybatis provided to achieve a variety of logging framework, these implementations are matching the Log interface methods defined by the interface, and ultimately to all external frame adapted Mybatis log logging package:

For example, for the realization Log4jImpl for the realization of org.apache.log4j.Logger it holds an instance, then all logging methods are commissioned to implement this instance.

public class Log4jImpl implements Log {
 
	private static final String FQCN = Log4jImpl.class.getName();
 
	private Logger log;
 
	public Log4jImpl(String clazz) {
		log = Logger.getLogger(clazz);
	}
 
	@Override
	public boolean isDebugEnabled() {
		return log.isDebugEnabled();
	}
 
	@Override
	public boolean isTraceEnabled() {
		return log.isTraceEnabled();
	}
 
	@Override
	public void error(String s, Throwable e) {
		log.log(FQCN, Level.ERROR, s, e);
	}
 
	@Override
	public void error(String s) {
		log.log(FQCN, Level.ERROR, s, null);
	}
 
	@Override
	public void debug(String s) {
		log.log(FQCN, Level.DEBUG, s, null);
	}
 
	@Override
	public void trace(String s) {
		log.log(FQCN, Level.TRACE, s, null);
	}
 
	@Override
	public void warn(String s) {
		log.log(FQCN, Level.WARN, s, null);
	}
 
}
复制代码

8, the decorator pattern

Decorative patterns (Decorator Pattern): dynamically to an object to add some extra responsibility (Responsibility), increased the object function, the decorative pattern is more flexible than a generation to achieve sub-class. Which may also be referred alias wrapper (the Wrapper), same as the alias adapter mode, but they apply to different situations. Depending on the decorative patterns of translation was also known as "painters model", which is an object-structured mode.

In mybatis, the cache function (org.apache.ibatis.cache.Cache) defined by the root interface Cache. Whole system using decorative design pattern, the basic functions and the cache data storage is implemented by PerpetualCache (org.apache.ibatis.cache.impl.PerpetualCache) persistent cache, then cache caching policy to PerpetualCache permanent decoration or the like through a series of convenient control. As shown below:

For decorative PerpetualCache standard decorators total of eight (all org.apache.ibatis.cache.decorators package):

  1. FifoCache: FIFO algorithm, caching collection policy
  2. LoggingCache: output cache hit log information
  3. LruCache: least recently used algorithm, caching collection policy
  4. ScheduledCache: scheduling cache, is responsible for the timing of clearing the cache
  5. SerializedCache: caching serialization and deserialization storage
  6. SoftCache: cache management policy based on soft reference implementation
  7. SynchronizedCache: synchronous cache decorator is used to prevent multiple threads concurrently access
  8. WeakCache: cache management policy based on weak references implemented

In addition, there is a special decorator TransactionalCache: transactional cache

As most persistence layer frameworks, mybatis same buffer cache and secondary cache into a

  • Level cache, also known as a local cache, the cache is permanently PerpetualCache type, save in the actuator (BaseExecutor), performed in turn in SqlSession (DefaultSqlSession), so the cache of the life cycle of the SqlSession are the same.
  • Secondary cache, called custom cache Cache class that implements the interface can be used as the secondary cache, may be configured so that a third party such as encache cache. Secondary cache to the namespace name space for its unique identifier is stored in the Configuration core configuration object.

The default type for the secondary cache object PerpetualCache, the default configuration if the cache type, mybatis automatically appended in accordance with a series of the decorator configuration.

Cited order between the Cache object:

SynchronizedCache–>LoggingCache–>SerializedCache–>ScheduledCache–>LruCache–>PerpetualCache

9, the iterator pattern

Iterator (Iterator) mode, also known as cursor (Cursor) mode. Defined GOF given to: provide a method for accessing a container (Container) object individual elements, without exposing the details of the object.

The interface is Java's Iterator iterator pattern, as long as the realization of this interface is equivalent to the application of iterative mode:

The property is PropertyTokenizer such Mybatis package heavyweight class, which is reflection package frequent references other classes to. This class implements the Iterator interface in use is frequently used hasNext Iterator interface function.

public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
	private String name;
	private String indexedName;
	private String index;
	private String children;
 
	public PropertyTokenizer(String fullname) {
		int delim = fullname.indexOf('.');
		if (delim > -1) {
			name = fullname.substring(0, delim);
			children = fullname.substring(delim + 1);
		} else {
			name = fullname;
			children = null;
		}
		indexedName = name;
		delim = name.indexOf('[');
		if (delim > -1) {
			index = name.substring(delim + 1, name.length() - 1);
			name = name.substring(0, delim);
		}
	}
 
	public String getName() {
		return name;
	}
 
	public String getIndex() {
		return index;
	}
 
	public String getIndexedName() {
		return indexedName;
	}
 
	public String getChildren() {
		return children;
	}
 
	@Override
	public boolean hasNext() {
		return children != null;
	}
 
	@Override
	public PropertyTokenizer next() {
		return new PropertyTokenizer(children);
	}
 
	@Override
	public void remove() {
		throw new UnsupportedOperationException(
				"Remove is not supported, as it has no meaning in the context of properties.");
	}
}
复制代码

It can be seen that a string type passed to the constructor, and provides a method iterator After traversing the parse string, it is a commonly used method class.

Reproduced in: https: //juejin.im/post/5d01f0e4f265da1bc23f726a

Guess you like

Origin blog.csdn.net/weixin_33847182/article/details/93182076