MyBatisPlus系列八:插件扩展

一、插件机制:
 Mybatis 通过插件(Interceptor) 可以做到拦截四大对象相关方法的执行,根据需求,完 成相关数据的动态改变。
 Executor
 StatementHandler
 ParameterHandler
 ResultSetHandler
二、插件原理:
 四大对象的每个对象在创建时,都会执行 interceptorChain.pluginAll(),会经过每个插 件对象的 plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四 大对象相关方法的执行,因为要执行四大对象的方法需要经过代理。
三、在spring配置文件中注册插件

<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
	<!-- 插件注册 -->
	<property name="plugins">
		<list>
			<!-- 注册分页插件 -->
			<bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
			<!-- 注册执行分析插件 -->
			<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
				<property name="stopProceed" value="true"></property>
			</bean>
			<!-- 注册性能分析插件 -->
			<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor">
				<property name="format" value="true"></property>
				<property name="maxTime" value="100"></property>
			</bean>
			<!-- 注册乐观锁插件 -->
			<bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor"></bean>
		</list>
	</property>
</bean>

1、分页插件:com.baomidou.mybatisplus.plugins.PaginationInterceptor

@Test
public void testPage() {
	Page<Employee> page = new Page<>(1,1);
	List<Employee > emps = 
			employeeMapper.selectPage(page, null);
	System.out.println(emps);
	System.out.println("总条数:" +page.getTotal());
	System.out.println("当前页码: "+  page.getCurrent());
	System.out.println("总页码:" + page.getPages());
	System.out.println("每页显示的条数:" + page.getSize());
	System.out.println("是否有上一页: " + page.hasPrevious());
	System.out.println("是否有下一页: " + page.hasNext());
	//将查询的结果封装到page对象中
	page.setRecords(emps);
}

控制台输出:

Preparing: SELECT COUNT(1) FROM tbl_employee
Parameters:
Preparing: SELECT id AS id,last_name AS lastName,email,gender,age FROM tbl_employee LIMIT 0,1   
Parameters: 
Total: 1
Time:6 ms - ID:com.atguigu.mp.mapper.EmployeeMapper.selectPage
 Execute SQL:
    SELECT
        id AS id,
        last_name AS lastName,
        email,
        gender,
        age 
    FROM
        tbl_employee LIMIT 0,
        1]
[Employee{, id=7, lastName=王五, [email protected], gender=0, age=null}]
总条数:3
当前页码: 1
总页码:3
每页显示的条数:1
是否有上一页: false
是否有下一页: true

原理分析:

@Intercepts({@Signature(
    type = StatementHandler.class,
    method = "prepare",
    args = {Connection.class, Integer.class}
)})
public class PaginationInterceptor extends SqlParserHandler implements Interceptor {
    private static final Log logger = LogFactory.getLog(PaginationInterceptor.class);
    private ISqlParser sqlParser;
    private boolean overflowCurrent = false;
    private String dialectType;
    private String dialectClazz;
    private boolean localPage = false;

    public PaginationInterceptor() {
    }

    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler)PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        this.sqlParser(metaObject);
        MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
        if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
            return invocation.proceed();
        } else {
            RowBounds rowBounds = (RowBounds)metaObject.getValue("delegate.rowBounds");
            if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
                if (!this.localPage) {
                    return invocation.proceed();
                }

                rowBounds = PageHelper.getPagination();
                if (rowBounds == null) {
                    return invocation.proceed();
                }
            }

            BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");
            String originalSql = boundSql.getSql();
            Connection connection = (Connection)invocation.getArgs()[0];
            DBType dbType = StringUtils.isNotEmpty(this.dialectType) ? DBType.getDBType(this.dialectType) : JdbcUtils.getDbType(connection.getMetaData().getURL());
            if (rowBounds instanceof Pagination) {
                Pagination page = (Pagination)rowBounds;
                boolean orderBy = true;
                if (page.isSearchCount()) {
                    SqlInfo sqlInfo = SqlUtils.getOptimizeCountSql(page.isOptimizeCountSql(), this.sqlParser, originalSql);
                    orderBy = sqlInfo.isOrderBy();
                    this.queryTotal(this.overflowCurrent, sqlInfo.getSql(), mappedStatement, boundSql, page, connection);
                    if (page.getTotal() <= 0L) {
                        return invocation.proceed();
                    }
                }

                String buildSql = SqlUtils.concatOrderBy(originalSql, page, orderBy);
                originalSql = DialectFactory.buildPaginationSql(page, buildSql, dbType, this.dialectClazz);
            } else {
                originalSql = DialectFactory.buildPaginationSql((RowBounds)rowBounds, originalSql, dbType, this.dialectClazz);
            }

            metaObject.setValue("delegate.boundSql.sql", originalSql);
            metaObject.setValue("delegate.rowBounds.offset", 0);
            metaObject.setValue("delegate.rowBounds.limit", 2147483647);
            return invocation.proceed();
        }
    }

    protected void queryTotal(boolean overflowCurrent, String sql, MappedStatement mappedStatement, BoundSql boundSql, Pagination page, Connection connection) {
        try {
            PreparedStatement statement = connection.prepareStatement(sql);
            Throwable var8 = null;

            try {
                DefaultParameterHandler parameterHandler = new MybatisDefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), boundSql);
                parameterHandler.setParameters(statement);
                long total = 0L;
                ResultSet resultSet = statement.executeQuery();
                Throwable var13 = null;

                try {
                    if (resultSet.next()) {
                        total = resultSet.getLong(1);
                    }
                } catch (Throwable var38) {
                    var13 = var38;
                    throw var38;
                } finally {
                    if (resultSet != null) {
                        if (var13 != null) {
                            try {
                                resultSet.close();
                            } catch (Throwable var37) {
                                var13.addSuppressed(var37);
                            }
                        } else {
                            resultSet.close();
                        }
                    }

                }

                page.setTotal(total);
                long pages = page.getPages();
                if (overflowCurrent && (long)page.getCurrent() > pages) {
                    page.setCurrent(1);
                }
            } catch (Throwable var40) {
                var8 = var40;
                throw var40;
            } finally {
                if (statement != null) {
                    if (var8 != null) {
                        try {
                            statement.close();
                        } catch (Throwable var36) {
                            var8.addSuppressed(var36);
                        }
                    } else {
                        statement.close();
                    }
                }

            }
        } catch (Exception var42) {
            logger.error("Error: Method queryTotal execution error !", var42);
        }

    }

    public Object plugin(Object target) {
        return target instanceof StatementHandler ? Plugin.wrap(target, this) : target;
    }

    public void setProperties(Properties prop) {
        String dialectType = prop.getProperty("dialectType");
        String dialectClazz = prop.getProperty("dialectClazz");
        String localPage = prop.getProperty("localPage");
        if (StringUtils.isNotEmpty(dialectType)) {
            this.dialectType = dialectType;
        }

        if (StringUtils.isNotEmpty(dialectClazz)) {
            this.dialectClazz = dialectClazz;
        }

        if (StringUtils.isNotEmpty(localPage)) {
            this.localPage = Boolean.valueOf(localPage);
        }

    }

    public PaginationInterceptor setDialectType(String dialectType) {
        this.dialectType = dialectType;
        return this;
    }

    public PaginationInterceptor setDialectClazz(String dialectClazz) {
        this.dialectClazz = dialectClazz;
        return this;
    }

    public PaginationInterceptor setOverflowCurrent(boolean overflowCurrent) {
        this.overflowCurrent = overflowCurrent;
        return this;
    }

    public PaginationInterceptor setSqlParser(ISqlParser sqlParser) {
        this.sqlParser = sqlParser;
        return this;
    }

    public PaginationInterceptor setLocalPage(boolean localPage) {
        this.localPage = localPage;
        return this;
    }
}

2、执行分析插件:com.baomidou.mybatisplus.plugins.SqlExplainInterceptor
 SQL 执行分析拦截器,只支持 MySQL5.6.3 以上版本。
 该插件的作用是分析 DELETE UPDATE 语句,防止 DELETE UPDATE 全表操作。
 只建议在开发环境中使用,不建议在生产环境使用。
 在插件的底层通过 SQL 语句分析命令:Explain 分析当前的 SQL 语句,根据结果集中的 Extra 列来断定当前是否全表操作。

@Test
public void testSQLExplain() {
	employeeMapper.delete(null); 
}

控制台输出:
在这里插入图片描述
原理分析:

@Intercepts({@Signature(
    type = Executor.class,
    method = "update",
    args = {MappedStatement.class, Object.class}
)})
public class SqlExplainInterceptor implements Interceptor {
    private static final Log logger = LogFactory.getLog(SqlExplainInterceptor.class);
    private final String minMySQLVersion = "5.6.3";
    private boolean stopProceed = false;

    public SqlExplainInterceptor() {
    }

    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement ms = (MappedStatement)invocation.getArgs()[0];
        if (ms.getSqlCommandType() == SqlCommandType.DELETE || ms.getSqlCommandType() == SqlCommandType.UPDATE) {
            Executor executor = (Executor)invocation.getTarget();
            Configuration configuration = ms.getConfiguration();
            Object parameter = invocation.getArgs()[1];
            BoundSql boundSql = ms.getBoundSql(parameter);
            Connection connection = executor.getTransaction().getConnection();
            String databaseVersion = connection.getMetaData().getDatabaseProductVersion();
            if (GlobalConfigUtils.getDbType(configuration).equals(DBType.MYSQL) && VersionUtils.compare("5.6.3", databaseVersion)) {
                logger.warn("Warn: Your mysql version needs to be greater than '5.6.3' to execute of Sql Explain!");
                return invocation.proceed();
            }
			//执行sql分析方法
            this.sqlExplain(configuration, ms, boundSql, connection, parameter);
        }

        return invocation.proceed();
    }

    protected void sqlExplain(Configuration configuration, MappedStatement mappedStatement, BoundSql boundSql, Connection connection, Object parameter) {
        StringBuilder explain = new StringBuilder("EXPLAIN ");
        explain.append(boundSql.getSql());
        String sqlExplain = explain.toString();
        StaticSqlSource sqlsource = new StaticSqlSource(configuration, sqlExplain, boundSql.getParameterMappings());
        Builder builder = new Builder(configuration, "explain_sql", sqlsource, SqlCommandType.SELECT);
        builder.resultMaps(mappedStatement.getResultMaps()).resultSetType(mappedStatement.getResultSetType()).statementType(mappedStatement.getStatementType());
        MappedStatement queryStatement = builder.build();
        DefaultParameterHandler handler = new DefaultParameterHandler(queryStatement, parameter, boundSql);

        try {
            PreparedStatement stmt = connection.prepareStatement(sqlExplain);
            Throwable var13 = null;

            try {
                handler.setParameters(stmt);
                ResultSet rs = stmt.executeQuery();
                Throwable var15 = null;

                try {
                    while(rs.next()) {
                        if (!"Using where".equals(rs.getString("Extra"))) {
                            if (this.isStopProceed()) {
                                throw new MybatisPlusException("Error: Full table operation is prohibited. SQL: " + boundSql.getSql());
                            }
                            break;
                        }
                    }
                } catch (Throwable var40) {
                    var15 = var40;
                    throw var40;
                } finally {
                    if (rs != null) {
                        if (var15 != null) {
                            try {
                                rs.close();
                            } catch (Throwable var39) {
                                var15.addSuppressed(var39);
                            }
                        } else {
                            rs.close();
                        }
                    }

                }
            } catch (Throwable var42) {
                var13 = var42;
                throw var42;
            } finally {
                if (stmt != null) {
                    if (var13 != null) {
                        try {
                            stmt.close();
                        } catch (Throwable var38) {
                            var13.addSuppressed(var38);
                        }
                    } else {
                        stmt.close();
                    }
                }

            }

        } catch (Exception var44) {
            throw new MybatisPlusException(var44);
        }
    }

    public Object plugin(Object target) {
        return target instanceof Executor ? Plugin.wrap(target, this) : target;
    }

    public void setProperties(Properties prop) {
        String stopProceed = prop.getProperty("stopProceed");
        if (StringUtils.isNotEmpty(stopProceed)) {
            this.stopProceed = Boolean.valueOf(stopProceed);
        }

    }

    public boolean isStopProceed() {
        return this.stopProceed;
    }

    public void setStopProceed(boolean stopProceed) {
        this.stopProceed = stopProceed;
    }
}

3、性能分析插件:com.baomidou.mybatisplus.plugins.PerformanceInterceptor
 性能分析拦截器,用于输出每条 SQL 语句及其执行时间。
 SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题。

@Test
public void testPerformance() {
	Employee employee = new Employee();
	employee.setLastName("王五");
	employee.setEmail("[email protected]");
	employee.setGender("0");
	employee.setAge(22);
	employeeMapper.insert(employee);
}

控制台输出:

Preparing: INSERT INTO tbl_employee ( last_name, email, gender, age ) VALUES ( ?, ?, ?, ? )   
Parameters: 王五(String), [email protected](String), 0(String), 22(Integer)
Updates: 1
Time:52 ms - ID:com.atguigu.mp.mapper.EmployeeMapper.insert
 Execute SQL:
    INSERT 
    INTO
        tbl_employee
        ( last_name, email, gender, age ) 
    VALUES
        ( '王五', '[email protected]', '0', 22 )]

原理分析:

@Intercepts({@Signature(
    type = StatementHandler.class,
    method = "query",
    args = {Statement.class, ResultHandler.class}
), @Signature(
    type = StatementHandler.class,
    method = "update",
    args = {Statement.class}
), @Signature(
    type = StatementHandler.class,
    method = "batch",
    args = {Statement.class}
)})
public class PerformanceInterceptor implements Interceptor {
    private static final Log logger = LogFactory.getLog(PerformanceInterceptor.class);
    private static final String DruidPooledPreparedStatement = "com.alibaba.druid.pool.DruidPooledPreparedStatement";
    private static final String T4CPreparedStatement = "oracle.jdbc.driver.T4CPreparedStatement";
    private static final String OraclePreparedStatementWrapper = "oracle.jdbc.driver.OraclePreparedStatementWrapper";
    private long maxTime = 0L;
    private boolean format = false;
    private boolean writeInLog = false;
    private Method oracleGetOriginalSqlMethod;
    private Method druidGetSQLMethod;

    public PerformanceInterceptor() {
    }

    public Object intercept(Invocation invocation) throws Throwable {
        Object firstArg = invocation.getArgs()[0];
        Statement statement;
        if (Proxy.isProxyClass(firstArg.getClass())) {
            statement = (Statement)SystemMetaObject.forObject(firstArg).getValue("h.statement");
        } else {
            statement = (Statement)firstArg;
        }

        MetaObject stmtMetaObj = SystemMetaObject.forObject(statement);

        try {
            statement = (Statement)stmtMetaObj.getValue("stmt.statement");
        } catch (Exception var20) {
            ;
        }

        if (stmtMetaObj.hasGetter("delegate")) {
            try {
                statement = (Statement)stmtMetaObj.getValue("delegate");
            } catch (Exception var19) {
                ;
            }
        }

        String originalSql = null;
        String stmtClassName = statement.getClass().getName();
        Class clazz;
        Object stmtSql;
        if ("com.alibaba.druid.pool.DruidPooledPreparedStatement".equals(stmtClassName)) {
            try {
                if (this.druidGetSQLMethod == null) {
                    clazz = Class.forName("com.alibaba.druid.pool.DruidPooledPreparedStatement");
                    this.druidGetSQLMethod = clazz.getMethod("getSql");
                }

                stmtSql = this.druidGetSQLMethod.invoke(statement);
                if (stmtSql != null && stmtSql instanceof String) {
                    originalSql = (String)stmtSql;
                }
            } catch (Exception var18) {
                ;
            }
        } else if ("oracle.jdbc.driver.T4CPreparedStatement".equals(stmtClassName) || "oracle.jdbc.driver.OraclePreparedStatementWrapper".equals(stmtClassName)) {
            try {
                if (this.oracleGetOriginalSqlMethod != null) {
                    stmtSql = this.oracleGetOriginalSqlMethod.invoke(statement);
                    if (stmtSql != null && stmtSql instanceof String) {
                        originalSql = (String)stmtSql;
                    }
                } else {
                    clazz = Class.forName(stmtClassName);
                    this.oracleGetOriginalSqlMethod = this.getMethodRegular(clazz, "getOriginalSql");
                    if (this.oracleGetOriginalSqlMethod != null) {
                        this.oracleGetOriginalSqlMethod.setAccessible(true);
                        if (this.oracleGetOriginalSqlMethod != null) {
                            Object stmtSql = this.oracleGetOriginalSqlMethod.invoke(statement);
                            if (stmtSql != null && stmtSql instanceof String) {
                                originalSql = (String)stmtSql;
                            }
                        }
                    }
                }
            } catch (Exception var17) {
                ;
            }
        }

        if (originalSql == null) {
            originalSql = statement.toString();
        }

        originalSql = originalSql.replaceAll("[\\s]+", " ");
        int index = this.indexOfSqlStart(originalSql);
        if (index > 0) {
            originalSql = originalSql.substring(index, originalSql.length());
        }

        long start = SystemClock.now();
        Object result = invocation.proceed();
        long timing = SystemClock.now() - start;
        Object target = PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(target);
        MappedStatement ms = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
        StringBuilder formatSql = new StringBuilder();
        formatSql.append(" Time:").append(timing);
        formatSql.append(" ms - ID:").append(ms.getId());
        formatSql.append("\n Execute SQL:").append(SqlUtils.sqlFormat(originalSql, this.format)).append("\n");
        if (this.isWriteInLog()) {
            if (this.getMaxTime() >= 1L && timing > this.getMaxTime()) {
                logger.error(formatSql.toString());
            } else {
                logger.debug(formatSql.toString());
            }
        } else {
            System.err.println(formatSql.toString());
            if (this.getMaxTime() >= 1L && timing > this.getMaxTime()) {
                throw new MybatisPlusException(" The SQL execution time is too large, please optimize ! ");
            }
        }

        return result;
    }

    public Object plugin(Object target) {
        return target instanceof StatementHandler ? Plugin.wrap(target, this) : target;
    }

    public void setProperties(Properties prop) {
        String maxTime = prop.getProperty("maxTime");
        String format = prop.getProperty("format");
        if (StringUtils.isNotEmpty(maxTime)) {
            this.maxTime = Long.parseLong(maxTime);
        }

        if (StringUtils.isNotEmpty(format)) {
            this.format = Boolean.valueOf(format);
        }

    }

    public long getMaxTime() {
        return this.maxTime;
    }

    public PerformanceInterceptor setMaxTime(long maxTime) {
        this.maxTime = maxTime;
        return this;
    }

    public boolean isFormat() {
        return this.format;
    }

    public PerformanceInterceptor setFormat(boolean format) {
        this.format = format;
        return this;
    }

    public boolean isWriteInLog() {
        return this.writeInLog;
    }

    public PerformanceInterceptor setWriteInLog(boolean writeInLog) {
        this.writeInLog = writeInLog;
        return this;
    }

    public Method getMethodRegular(Class<?> clazz, String methodName) {
        if (Object.class.equals(clazz)) {
            return null;
        } else {
            Method[] arr$ = clazz.getDeclaredMethods();
            int len$ = arr$.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                Method method = arr$[i$];
                if (method.getName().equals(methodName)) {
                    return method;
                }
            }

            return this.getMethodRegular(clazz.getSuperclass(), methodName);
        }
    }

    private int indexOfSqlStart(String sql) {
        String upperCaseSql = sql.toUpperCase();
        Set<Integer> set = new HashSet();
        set.add(upperCaseSql.indexOf("SELECT "));
        set.add(upperCaseSql.indexOf("UPDATE "));
        set.add(upperCaseSql.indexOf("INSERT "));
        set.add(upperCaseSql.indexOf("DELETE "));
        set.remove(-1);
        if (CollectionUtils.isEmpty(set)) {
            return -1;
        } else {
            List<Integer> list = new ArrayList(set);
            Collections.sort(list, new Comparator<Integer>() {
                public int compare(Integer o1, Integer o2) {
                    return o1.compareTo(o2);
                }
            });
            return (Integer)list.get(0);
        }
    }
}

4、乐观锁插件:com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor
1、 如果想实现如下需求: 当要更新一条记录的时候,希望这条记录没有被别人更新。
2、乐观锁的实现原理:
 取出记录时,获取当前version
 更新时,带上这个version
 执行更新时,set version = yourVersion+1 where version = yourVersion
 如果 version 不对,就更新失败
3、@Version 用于注解实体字段,必须要有。
测试:
 在实体Employee添加version属性:

@Version
private Integer version ;

public Integer getVersion() {
	return version;
}

public void setVersion(Integer version) {
	this.version = version;
}

 在表tbl_employee添加version字段:
在这里插入图片描述

@Test
public void testOptimisticLocker() {
	Employee employee = new Employee();
	employee.setId(7);
	employee.setLastName("王五");
	employee.setEmail("[email protected]");
	employee.setGender("0");
	employee.setAge(22);
	employee.setVersion(1);
	employeeMapper.updateById(employee);
}

控制台输出:

Preparing: UPDATE tbl_employee SET last_name=?, email=?, gender=?, age=?, version=? WHERE id=? and version=?
Parameters: 王五(String), [email protected](String), 0(String), 22(Integer), 2(Integer), 7(Integer), 1(Integer)
Updates: 1 
Time:33 ms - ID:com.atguigu.mp.mapper.EmployeeMapper.updateById
 Execute SQL:
    UPDATE
        tbl_employee 
    SET
        last_name='王五',
        email='[email protected]',
        gender='0',
        age=22,
        version=2 
    WHERE
        id=7 
        and version=1]

在这里插入图片描述
原理分析:

@Intercepts({@Signature(
    type = Executor.class,
    method = "update",
    args = {MappedStatement.class, Object.class}
)})
public class OptimisticLockerInterceptor implements Interceptor {
    private final Map<Class<?>, EntityField> versionFieldCache = new ConcurrentHashMap();
    private final Map<Class<?>, List<EntityField>> entityFieldsCache = new ConcurrentHashMap();
    private static final String MP_OPTLOCK_VERSION_ORIGINAL = "MP_OPTLOCK_VERSION_ORIGINAL";
    private static final String MP_OPTLOCK_VERSION_COLUMN = "MP_OPTLOCK_VERSION_COLUMN";
    public static final String MP_OPTLOCK_ET_ORIGINAL = "MP_OPTLOCK_ET_ORIGINAL";
    private static final String NAME_ENTITY = "et";
    private static final String NAME_ENTITY_WRAPPER = "ew";
    private static final String PARAM_UPDATE_METHOD_NAME = "update";

    public OptimisticLockerInterceptor() {
    }

    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement)args[0];
        if (SqlCommandType.UPDATE != ms.getSqlCommandType()) {
            return invocation.proceed();
        } else {
            Object param = args[1];
            if (param instanceof HashMap) {
                HashMap map = (HashMap)param;
                Wrapper ew = null;
                if (map.containsKey("ew")) {
                    ew = (Wrapper)map.get("ew");
                }

                Object et = null;
                if (map.containsKey("et")) {
                    et = map.get("et");
                }

                if (ew != null) {
                    Object entity = ew.getEntity();
                    if (entity != null) {
                        Class<?> entityClass = ClassUtils.getUserClass(entity.getClass());
                        EntityField ef = this.getVersionField(entityClass);
                        Field versionField = ef == null ? null : ef.getField();
                        if (versionField != null) {
                            Object originalVersionVal = versionField.get(entity);
                            if (originalVersionVal != null) {
                                versionField.set(et, this.getUpdatedVersionVal(originalVersionVal));
                            }
                        }
                    }
                } else if (et != null) {
                    String methodId = ms.getId();
                    String updateMethodName = methodId.substring(ms.getId().lastIndexOf(".") + 1);
                    if ("update".equals(updateMethodName)) {
                        return invocation.proceed();
                    }

                    Class<?> entityClass = ClassUtils.getUserClass(et.getClass());
                    EntityField entityField = this.getVersionField(entityClass);
                    Field versionField = entityField == null ? null : entityField.getField();
                    Object originalVersionVal;
                    if (versionField != null && (originalVersionVal = versionField.get(et)) != null) {
                        TableInfo tableInfo;
                        for(tableInfo = TableInfoHelper.getTableInfo(entityClass); null == tableInfo && null != entityClass; tableInfo = TableInfoHelper.getTableInfo(entityClass)) {
                            entityClass = ClassUtils.getUserClass(entityClass.getSuperclass());
                        }

                        Map<String, Object> entityMap = new HashMap();
                        List<EntityField> fields = this.getEntityFields(entityClass);
                        Iterator i$ = fields.iterator();

                        while(i$.hasNext()) {
                            EntityField ef = (EntityField)i$.next();
                            Field fd = ef.getField();
                            if (fd.isAccessible()) {
                                entityMap.put(fd.getName(), fd.get(et));
                                if (ef.isVersion()) {
                                    versionField = fd;
                                }
                            }
                        }

                        String versionPropertyName = versionField.getName();
                        List<TableFieldInfo> fieldList = tableInfo.getFieldList();
                        String versionColumnName = entityField.getColumnName();
                        if (versionColumnName == null) {
                            Iterator i$ = fieldList.iterator();

                            while(i$.hasNext()) {
                                TableFieldInfo tf = (TableFieldInfo)i$.next();
                                if (versionPropertyName.equals(tf.getProperty())) {
                                    versionColumnName = tf.getColumn();
                                }
                            }
                        }

                        if (versionColumnName != null) {
                            entityField.setColumnName(versionColumnName);
                            entityMap.put(versionField.getName(), this.getUpdatedVersionVal(originalVersionVal));
                            entityMap.put("MP_OPTLOCK_VERSION_ORIGINAL", originalVersionVal);
                            entityMap.put("MP_OPTLOCK_VERSION_COLUMN", versionColumnName);
                            entityMap.put("MP_OPTLOCK_ET_ORIGINAL", et);
                            map.put("et", entityMap);
                        }
                    }
                }
            }

            return invocation.proceed();
        }
    }

    protected Object getUpdatedVersionVal(Object originalVersionVal) {
        Class<?> versionValClass = originalVersionVal.getClass();
        if (Long.TYPE.equals(versionValClass)) {
            return (Long)originalVersionVal + 1L;
        } else if (Long.class.equals(versionValClass)) {
            return (Long)originalVersionVal + 1L;
        } else if (Integer.TYPE.equals(versionValClass)) {
            return (Integer)originalVersionVal + 1;
        } else if (Integer.class.equals(versionValClass)) {
            return (Integer)originalVersionVal + 1;
        } else if (Date.class.equals(versionValClass)) {
            return new Date();
        } else {
            return Timestamp.class.equals(versionValClass) ? new Timestamp(System.currentTimeMillis()) : originalVersionVal;
        }
    }

    public Object plugin(Object target) {
        return target instanceof Executor ? Plugin.wrap(target, this) : target;
    }

    public void setProperties(Properties properties) {
    }

    private EntityField getVersionField(Class<?> parameterClass) {
        synchronized(parameterClass.getName()) {
            if (this.versionFieldCache.containsKey(parameterClass)) {
                return (EntityField)this.versionFieldCache.get(parameterClass);
            } else {
                EntityField field = this.getVersionFieldRegular(parameterClass);
                if (field != null) {
                    this.versionFieldCache.put(parameterClass, field);
                    return field;
                } else {
                    return null;
                }
            }
        }
    }

    private EntityField getVersionFieldRegular(Class<?> parameterClass) {
        if (parameterClass != Object.class) {
            Field[] arr$ = parameterClass.getDeclaredFields();
            int len$ = arr$.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                Field field = arr$[i$];
                if (field.isAnnotationPresent(Version.class)) {
                    field.setAccessible(true);
                    return new EntityField(field, true);
                }
            }

            return this.getVersionFieldRegular(parameterClass.getSuperclass());
        } else {
            return null;
        }
    }

    private List<EntityField> getEntityFields(Class<?> parameterClass) {
        if (this.entityFieldsCache.containsKey(parameterClass)) {
            return (List)this.entityFieldsCache.get(parameterClass);
        } else {
            List<EntityField> fields = this.getFieldsFromClazz(parameterClass, (List)null);
            this.entityFieldsCache.put(parameterClass, fields);
            return fields;
        }
    }

    private List<EntityField> getFieldsFromClazz(Class<?> parameterClass, List<EntityField> fieldList) {
        if (fieldList == null) {
            fieldList = new ArrayList();
        }

        List<Field> fields = ReflectionKit.getFieldList(parameterClass);
        Iterator i$ = fields.iterator();

        while(i$.hasNext()) {
            Field field = (Field)i$.next();
            field.setAccessible(true);
            if (field.isAnnotationPresent(Version.class)) {
                ((List)fieldList).add(new EntityField(field, true));
            } else {
                ((List)fieldList).add(new EntityField(field, false));
            }
        }

        return (List)fieldList;
    }
}

猜你喜欢

转载自blog.csdn.net/lizhiqiang1217/article/details/89740185