Analysis of MyBatis Plug-in Mechanism

Posted by e33basketball on Sun, 23 Jun 2019 21:42:51 +0200

The videos of the following open lessons have been recorded, and students who need them can leave messages.

MyBatis is a framework with strong flexibility. MyBatis operates on the persistence layer by providing a simple and easy-to-use plug-in extension mechanism with the help of four components (Executor, Statement Handler, ParameterHandler, Result SetHandler).

MyBatis supports plug-ins to intercept the four core components. For MyBatis, plug-ins are interceptors to enhance the functions of the core components. The enhanced functions are essentially realized by means of the underlying dynamic proxy. In other words, the four main objects in MyBatis are proxy objects.

Brief Introduction of Four Core Components

Four core components of MyBatis:

  • ParameterHandler: Class that handles parameters of SQL
  • ResultSetHandler: Class that handles the return result set of SQL
  • StatementHandler: Class for handling database SQL statements
  • Executor: Executor class for performing add, delete, and change checks

Principle of MyBatis Plug-in

  1. MyBatis plug-in handles interception with the help of the responsibility chain model
  2. Using dynamic proxy to package the target object to achieve the purpose of interception

intercept

How do plug-ins intercept and add additional functionality? In the case of ParameterHandler

 public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object object, BoundSql sql, InterceptorChain interceptorChain){
        ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,object,sql);
        parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
        return parameterHandler;
    }
public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

IntereptorChain saves all interceptors, which were created when MyBatis was initialized.

The interceptors in the interceptor chain are called to intercept or enhance the target in turn.

The target in interceptor.plugin(target) can be understood as the four components in MyBatis, and the target returned is the object after being re-proxied.

Plug-in Interface

MyBatis Plug-in Interface-Interceptor

  1. intercept() method, the core method of plug-in
  2. plugin() method to generate the target proxy object
  3. setProperties() method, passing the parameters required by the plug-in

Instances of plug-ins

Plug-in development requires the following steps

  1. Custom plug-ins need to implement the above interfaces
  2. Add the @Intercepts annotation (which core component plug-ins are declared and which methods are extended)
  3. Configure plug-ins in xml files
**
 * Plug-in Signature, Tell MyBatis Which method is the plug-in used to intercept that object?
 **/
@Intercepts(
        {
                @Signature(
                        type = StatementHandler.class,
                        method = "parameterize",
                        args = Statement.class
                )
        }
)
public class MyIntercepts implements Interceptor {
    /**
     * Target Interception Method for Target Objects
     *
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("Enter a custom interceptor to intercept the target object" + invocation + invocation.getMethod() + invocation.getTarget());
        return invocation.proceed();
    }

    /**
     * Wrapping the target object to create the proxy object for the target object
     *
     * @Param target For the object to intercept
     * @Return Proxy object
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("custom plugin Method, the target object to be wrapped" + target.toString() + target.getClass());
        return Plugin.wrap(target, this);
    }

    /**
     * Get the properties of the configuration file
     *
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("Initialization parameters for custom plug-ins" + properties);
    }
}

Configure plug-ins in mybatis-config.xml

    <!-- Custom plug-in -->
    <plugins>
        <plugin interceptor="com.boxuegu.javaee.mybatissourcelearn.MyIntercepts">
            <property name="test" value="testvalue"/>
        </plugin>
    </plugins>

Call the query method, which returns the ResultSet

public class Test {
    public static void main(String[] args) {
        //1. Loading configuration files
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }

        //2. Get sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //3. Get sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
            //Execute sql statements directly through xml files
            //Employee employee = sqlSession.selectOne("com.boxuegu.javaee.mybatissourcelearn.dao.EmployeeMapper.getEmployeeById", 1);
            //alt+shift+L introduce local variables;
            Thread thread = new Thread(()-> System.out.println("test"));
            //4. Realization of Getting mapper Interface
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            System.out.println("mapper::::" + mapper.getClass());

            //5. Executing sql statements
            Employee employee = mapper.getEmployeeById(1);
            System.out.println(employee);
        } finally {
            sqlSession.close();
        }
    }
}

Output results

Initialization parameters for custom plug-ins{test=testvalue}
//Customize the plugin method to wrap the target object org.apache.ibatis.executor.CachingExecutor@46f5f779 class org.apache.ibatis.executor.CachingExecutor
mapper::::class com.sun.proxy.$Proxy3
//Custom plugin method, the target object to be wrapped is org.apache.ibatis.scripting.defaults.DefaultParameterHandler@1bc6a36eclass org.apache.ibatis.scripting.defaults.DefaultParameterHandler
//Custom plugin method, the target object to be wrapped is org.apache.ibatis.executor.resultset.DefaultResultSetHandler@387c703bclass org.apache.ibatis.executor.resultset.DefaultResultSetHandler
//Custom plugin method, the target object to be wrapped is org.apache.ibatis.executor.statement.RoutingStatementHandler@c39f790class org.apache.ibatis.executor.statement.RoutingStatementHandler
Wed Jun 19 18:14:24 CST 2019 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
//Enter a custom interceptor to intercept the target object org.apache.ibatis.plugin.Invocation@50f8360dpublic Abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize (java.sql.Statement) throws java.sql.SQL Exceptionorg.apache.ibatis.executor.statement.RoutingHandler@c39f790
Employee{id=1, lastName='zhangsan', email='zhangsan@itcast.cn', gender='1'}

Multi-plug-in development

  1. When creating proxy objects, wrap them in the order in which plug-ins are configured
  2. After the target method is executed, it is executed according to the reverse of the agent.

Summary

  1. Follow the principle that plug-ins should not be used as much as possible because the underlying design will be modified

  2. Plug-in is the responsibility chain mode of the generated layer-by-layer proxy object, which is implemented by reflection mechanism.

  3. Plug-ins should be written comprehensively, especially when multiple plug-in layer agents are involved.

Topics: Mybatis Apache SQL xml