java开源:玩转mybatis拦截器
1、创建并实现拦截器
1.1、步骤一:创建拦截器
MyBatis中创建拦截器必需要有两个元素
元素1:实现org.apache.ibatis.plugin.Interceptor接口
元素2:实现拦截器签名(这个签名比较复杂,咱们后面再单独介绍)
HelloInterceptor.java
package cn.zhao.interceptor;
import java.lang.reflect.Method;
import java.sql.Statement;
import java.util.Properties;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
//下面配置方法签名(可以是多个)
@Intercepts({
@Signature(
type=ResultSetHandler.class, //一个结果集处理的接口
method = "handleResultSets", //除存储过程 及返回值类型为Cursor以外的查询方法中被调用
args={Statement.class} //这个方法中必需传的值
)
})
public class HelloInterceptor implements Interceptor {
/**
* 这个方法就是运行时的拦截方法(invocation中有很多有用的信息)
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("执行到了intercept...");
Object target = invocation.getTarget();//获取当前被拦截的对象
Method method = invocation.getMethod();//被拦截的方法
Object[] args = invocation.getArgs(); //方法中的参数
//proceed:实际上执行了 method.invoke(target,args);
Object result = invocation.proceed();
System.out.println(result);
return result;
}
/**
* 方法中参数target就是拦截器要拦截的对象
* 调用时机:创建被拦截的接口实现类时被调用
*
*/
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
/**
* 用来传递插件的参数,可以通过参数改变 插件的行为
* 这个参数需要在 mybatis.xml中进行配置
* 调用 时机:拦截器初始化的时候这里就可以拿到值
*/
@Override
public void setProperties(Properties properties) {
System.out.println(properties.getProperty("prop1"));
}
}
1.2、步骤二:配置拦截器
Mybatis.xml:
<?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>
<properties resource="db.properties" />
<!-- 配置插件 -->
<plugins>
<plugin interceptor="cn.zhao.interceptor.HelloInterceptor">
<!-- 这里配置的就是参数 -->
<property name="prop1" value="value1"/>
<property name="prop2" value="value2"/>
</plugin>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/zhao/mapping/UserMapper.xml"/>
</mappers>
</configuration>
1.3、步骤三:测试
@Test
public void testSearch() throws Exception {
SqlSession session = MyBatisUtils.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.selectAll();
System.out.println(users);
session.commit();
session.close();
}
1.4、结果(查询的时候可以找到相应的拦截器了)
value1
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
执行到了intercept...
[User [id=2, name=xxxxxxxx], User [id=3, name=yyyyyyyyyyyyy], User [id=4, name=yyyyyyyyyyyyy], User [id=5, name=yyyyyyyyyyyyy]]
2、拦截器中的方法
2.1、setProperties(Properties properties)
这个方法主要是可以拿到配置文件中的参数,我们可以根据这些参数进行相应的操作
<!-- 配置插件 -->
<plugins>
<plugin interceptor="cn.zhao.interceptor.HelloInterceptor">
<!-- 这里配置的就是参数 -->
<property name="prop1" value="MySql"/>
<property name="prop2" value="Oracle"/>
</plugin>
</plugins>
通过相应的代码就可以得到上面的参数,当拦截器初始化的时候可以拿到值。
2.2、Object plugin(Object target)
里面的target就是拦截器要拦截的对象,创建被拦截的接口实现类时被调用,这个方法实现很简单,直接调用就可以以了。
Plugin.warp方法会自动 判断拦截器的签名和被拦截对象 接口是否匹配,只有匹配的情况下才会使用动态代理拦截目标对象,这个方法不需要做任何的逻辑判断。
2.3、Object intercept(Invocation invocation) throws Throwable
这个算是核心方法,它可以拿到被拦截的对象,方法,参数等等,我们修改结果,创建功能也一般是在这个方法中完成。
3、拦截器的签名配置认识
签名指的就是咱们配置拦截器上面的注解,这个注解是写拦截器的时候必需要配置的,其实就是抓住这些拦截器的时机。接下来,我们来介绍一下这个签名:
基本格式:
@Intercepts({
@Signature(
type=签名类型.class,
method = "这个类型对应的方法",
args={参数}
),
... //注:这个签名是可以直接配置多个的
})
签名类型分别有: Executor.class,ResultSetHandler.class,ParameterHandler.class,StatementHandler.class 这四种方式 ,每种方式对应不同的method方法,每个方法的参数又不一样(这里方法中的参数方法都是对应上的,根据相应的要求加上即可)
3.1、Executor接口
3.1.1、对应的Method
update:会在所有的insert,update,delete执行时被调用
@Signature(
type=Executor.class,
method = "update",
args={MappedStatement.class,Object.class}
)
query:会在所有select查询方法调用时被执行(这个是最常用的被拦截的方法)
@Signature(
type=Executor.class,
method = "query",
args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class}
)
queryCursor:返回值类型为Cursor时被调用
@Signature(
type=Executor.class,
method = "queryCursor",
args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class}
)
flushStatements:在SqlSession方法调用 flushStatements方法时调用
@Signature(
type=Executor.class,
method = "flushStatements",
args={}
)
后面几个和上面的flushStatements使用方式一样,只是改方法名,调用时机不一样,用得都不多
commit:在SqlSession方法调用 commit方法时调用
rollback:在SqlSession方法调用 rollback方法时调用
close:延时加载执行查询方法前被执行
3.2、ResultSetHandler接口
3.2.1、对应的Method
handleResultSets:除存储过程及返回值类型为Cursor以外的查询方法中被调用
对于拦截处理查询结果非常有用(被调用的位置在处理二级缓存之前)
@Signature(
type=ResultSetHandler.class,
method = "handleResultSets",
args={Statement.class}
)
handleOutputParameters:只在使用存储过程处理出参时被调用(用外不大)_
3.3、ParameterHandler接口
3.3.1、对应的Method
getParameterObject:只在执行存储过程处理参数的时候调用
@Signature(
type=ParameterHandler.class,
method = "getParameterObject",
args={}
)
setParameters:所有数据库方法设置SQL参数时被调用
@Signature(
type=ParameterHandler.class,
method = "setParameters",
args={PreparedStatement.class}
)
3.4、StatementHandler
3.4.1、对应的Method
prepare:在数据库执行前被调用
@Signature(
type=StatementHandler.class,
method = "prepare",
args={Connection.class,Integer.class}
)
Parameterize:在prepare方法之后执行,用于处理参数信息
@Signature(
type=StatementHandler.class,
method = "Parameterize",
args={Statement.class}
)
query:执行select方法时调用
@Signature(
type=StatementHandler.class,
method = "prepare",
args={Statement.class,ResultHandler.class}
)