MyBatis插件开发
来源:互联网 发布:网络进度计划编制软件 编辑:程序博客网 时间:2024/06/18 18:03
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback,getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
常用的插件有分页插件com.github.pagehelper.PageInterceptor。下面自定义个打印sql的插件。
通过对 MyBatis org.apache.ibatis.executor.statement.StatementHandler 中的prepare 方法进行拦截即可。
prepare 方法签名如下:
Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
自定义类实现org.apache.ibatis.plugin.Interceptor接口,Interceptor接口代码如下:
public interface Interceptor { Object intercept(Invocation invocation) throws Throwable; Object plugin(Object target); void setProperties(Properties properties);}
每一个拦截器都必须实现上面的三个方法,其中:
1) Object intercept(Invocation invocation)是实现拦截逻辑的地方,内部要通过invocation.proceed()调用下一个拦截器拦截目标方法。
2) Object plugin(Object target) 就是用当前这个拦截器生成对目标target的代理,实际是通过Plugin.wrap(target,this) 来完成的,把目标target和拦截器this传给了包装函数。
3) setProperties(Properties properties)用于设置额外的参数,参数配置在拦截器的Properties节点里。
注解里描述的是指定拦截方法的签名 [type,method,args] (即对哪种对象的哪种方法进行拦截),它在拦截前用于决断。
示例拦截器代码如下:
package com.cuisea.mybatis;import org.apache.ibatis.executor.statement.StatementHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.plugin.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.sql.Connection;import java.util.Properties;/** * Mybatis支持对Executor、StatementHandler、PameterHandler和ResultSetHandler 接口进行拦截,也就是说会对这4种对象进行代理 * MyBatis插件 打印sql * Created by cuisea on 2017/7/18. */@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class}) })public class SQLStatsInterceptor implements Interceptor{ private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); BoundSql boundSql = statementHandler.getBoundSql(); String sql = boundSql.getSql(); logger.info("mybatis intercept sql:{}", sql); return invocation.proceed(); } @Override public Object plugin(Object o) { logger.info("mybatis intercept plugin "+o.getClass().getName()); return Plugin.wrap(o, this); } @Override public void setProperties(Properties properties) { String dialect = properties.getProperty("dialect"); logger.info("mybatis intercept dialect:{}", dialect); }}
下面就要配置插件,有两种配置方式:
第一种:在MyBatis的配置文件mybatis-conf.xml的plugins节点下配置
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <plugins> <plugin interceptor="com.cuisea.mybatis.SQLStatsInterceptor"> <property name="dialect" value="mysql"></property> </plugin> </plugins></configuration>
第二种:在spring配置文件spring-mybatis.xml中配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <!-- 扫描service包下所有使用注解的类型 --> <context:component-scan base-package="com.cuisea.service"/> <!-- 配置数据库相关参数properties的属性:${url} --> <context:property-placeholder location="classpath:jdbc.properties" ignore-resource-not-found="true"/> <!-- 数据库连接池c3p0--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="maxPoolSize" value="${c3p0.maxPoolSize}"/> <property name="minPoolSize" value="${c3p0.minPoolSize}"/> <property name="autoCommitOnClose" value="${c3p0.autoCommitOnClose}"/> <property name="checkoutTimeout" value="${c3p0.checkoutTimeout}"/> <property name="acquireRetryAttempts" value="${c3p0.acquireRetryAttempts}"/> </bean> <!-- 配置SqlSessionFactory对象 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入数据库连接池 --> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:mybatis-config.xml" /> <!-- 扫描model包 使用别名,这样在mapper文件中可以省略包名;否则parameterType,resultType必须使用类的全限定名 --> <property name="typeAliasesPackage" value="com.cuisea.model"/> <!-- 扫描sql配置文件:mapper需要的xml文件 --> <property name="mapperLocations" value="classpath:mapper/*.xml"/> <property name="plugins"> <array> <bean class="com.cuisea.mybatis.SQLStatsInterceptor"> <property name="properties"> <!-- config params as the following --> <value> dialect=mysql </value> </property> </bean> </array> </property> </bean> <!-- 配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 注入sqlSessionFactory --> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!-- 给出需要扫描Dao接口包 --> <property name="basePackage" value="com.cuisea.dao"/> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入数据库连接池 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置基于注解的声明式事务 --> <tx:annotation-driven transaction-manager="transactionManager"/></beans>
测试运行结果如下:
第一种配置方式通过org.apache.ibatis.builder.xml.XMLConfigBuilder解析xml文件将自定义plugin加载到org.apache.ibatis.session.Configuration实例的interceptorChain字段中
private void pluginElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { String interceptor = child.getStringAttribute("interceptor"); Properties properties = child.getChildrenAsProperties(); Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance(); interceptorInstance.setProperties(properties); configuration.addInterceptor(interceptorInstance); } } }
第二种方式是在实例化org.mybatis.spring.SqlSessionFactoryBean的时候添加进去的,protected SqlSessionFactory buildSqlSessionFactory()的代码片段如下:
if (!isEmpty(this.plugins)) { for (Interceptor plugin : this.plugins) { configuration.addInterceptor(plugin); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Registered plugin: '" + plugin + "'"); } } }
参考资料:http://blog.csdn.net/top_code/article/details/55520948
- MyBatis插件开发
- MyBatis初窥:插件开发
- mybatis插件开发
- Mybatis插件开发原理
- MyBatis插件开发
- MyBatis 教程 - MyBatis插件(Plugins)开发
- mybatis插件开发——分表插件
- mybatis插件
- Mybatis插件
- Mybatis插件
- mybatis插件
- MyBatis整体预览(二)(关于自己开发插件与mybatis 的整合)
- 【Mybatis】mybatis插件源码分析
- MyBatis-MyEclipse+MyBatis-Generator插件
- 深入浅出Mybatis-插件原理
- Mybatis分页插件
- 深入浅出Mybatis-插件原理
- Mybatis分页插件 - 示例
- mysql分区实践
- Properties读写属性文件
- css媒体查询 @media适配不同大小窗口
- 前端一点点
- POJ_1006_Biorhythms
- MyBatis插件开发
- Python OOP中如何在继承中避免代码重复设计
- 苹果酝酿取消打赏抽成:不再强推应用内购买,视为个人赠予
- 二维数组遍历求和操作:用二重循环求出二维数组b所有元素的和。
- mybatis学习第一次使用
- 找出比N小的最大质数
- Guava
- Integer和int相关
- 网站访问速度慢的排查方法