mybatis custom plug-in development explain

mybatis very powerful plug-ins, you can let us not intrusive to SQL execution to intervene, rewritten from SQL statements, parameter injection, each returned result set and other key areas, typically including inspection and access control injection, a read-only database mapping, K / V translations, rewriting dynamic SQL.

MyBatis supports default method for performing a method interception on 4 large object (Executor, StatementHandler, ParameterHandler, ResultSetHandler), specific support for:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

Specific methods can be found in the definition of signature of every class method, not described in detail here started. After these four classes are created not return directly, but creating executed interceptorChain.pluginAll (parameterHandler) before returning. As follows:

//Configuration 中
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
}
​
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
                                            ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
}
​
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
}
​
public Executor newExecutor(Transaction transaction) {
    return newExecutor(transaction, defaultExecutorType);
}
​
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
        executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
        executor = new ReuseExecutor(this, transaction);
    } else {
        executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
        executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

Write Interceptor implementation class

Executor interceptor

@Intercepts({
        // @Signature(type = Executor.class, method = /* org.apache.ibatis.executor.Executor中定义的方法,参数也要对应 */"update", args = { MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,RowBounds.class, ResultHandler.class }) })
public class SelectPruningColumnPlugin implements Interceptor {
    public static final ThreadLocal<ColumnPruning> enablePruning = new ThreadLocal<ColumnPruning>(){
        @Override
        protected ColumnPruning initialValue()
        {
            return null;
        }
    };
    
    Logger logger = LoggerFactory.getLogger(SelectPruningColumnPlugin.class);
    
    static int MAPPED_STATEMENT_INDEX = 0;// 这是对应上面的args的序号
    static int PARAMETER_INDEX = 1;
    static int ROWBOUNDS_INDEX = 2;
    static int RESULT_HANDLER_INDEX = 3;
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if(enablePruning.get () =! null && enablePruning.get () isEnablePruning ().) { 
            Object [] queryArgs = invocation.getArgs (); 
            MappedStatement mappedStatement = (MappedStatement) queryArgs [MAPPED_STATEMENT_INDEX]; 
            Object Parameter = queryArgs [PARAMETER_INDEX] ; 
            boundSql boundSql = mappedStatement.getBoundSql (the Parameter); 
            String SQL = boundSql.getSql (); // get to SQL, adjusted 
            String name = mappedStatement.getId (); 
            logger.debug ( "intercept method name is:" + name + ", sql is" + sql + ", the parameter is" +JsonUtils.toJson (the Parameter));
            ExecSQL String 
                String prop = pruningColumn (enablePruning.get () getReserveColumns (), SQL.); 
            Logger.debug ( "SQL revised is:" + execSQL); 

            // re new to a query like 
            BoundSql newBoundSql = new BoundSql (mappedStatement .getConfiguration (), execSQL, boundSql.getParameterMappings (), boundSql.getParameterObject ());
             // the new inquiry into the statement in 
            mappedStatement new MS = copyFromMappedStatement (mappedStatement, new new BoundSqlSqlSource (newBoundSql));
             for (ParameterMapping Mapping: boundSql .getParameterMappings ()) { = mapping.getProperty ();
                 IF(boundSql.hasAdditionalParameter (prop)) { 
                    newBoundSql.setAdditionalParameter (prop, boundSql.getAdditionalParameter (prop)); 
                } 
            } 
            queryArgs [MAPPED_STATEMENT_INDEX] = New MS;
             // because paging query relates PageHelper plug can not be set to null, business context requires after the execution is completed is set to null
 //             enablePruning.set (null); 
        } 
        Object Result = invocation.proceed ();
         return Result; 
    } 
    @Override 
    public Object plugin (Object target) {
         return Plugin.wrap (target, the this ); 
    }
    @Override
    public void setProperties(Properties properties) {
    }

ResultSetHandler interceptor

@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = { Statement.class}) })
public class OptMapPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        Statement stmt = (Statement) invocation.getArgs()[0];
        if (target instanceof DefaultResultSetHandler) {
            DefaultResultSetHandler resultSetHandler = (DefaultResultSetHandler) target;
            Class clz = resultSetHandler.getMappedStatement().getResultMaps().get(0).getType();
            if (clz == OptMap.class) {
                List<Object> resultList = new ArrayList<Object>();
                OptMap optMap = new OptMap();
                resultList.add(optMap);
                resultSet2OptMap(resultSetHandler.getConfiguration(),resultSetHandler,optMap,stmt.getResultSet());
                return resultList;
            }
            return invocation.proceed();
        }
        //If no intercept processing logic is executed by default 
        return invocation.proceed (); 
    }

 

Finally, the plug-in configuration to mybatis-config.xml as follows:

<!-- mybatis-config.xml  注册插件-->
<plugins>
    <plugin interceptor="io.yidoo.mybatis.plugin.SelectPruningColumnPlugin">
        <property name="someProperty" value="100"/>
    </plugin>
</plugins>

 

Guess you like

Origin www.cnblogs.com/zhjh256/p/11516878.html