1.mybatis拦截器介绍
拦截器可在mybatis进行sql底层处理的时候执行额外的逻辑,最常见的就是分页逻辑、对结果集进行处理过滤敏感信息等。- public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return parameterHandler;
- }
- public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> ResultHandler resultHandler, BoundSql boundSql) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return resultSetHandler;
- }
- public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return statementHandler;
- }
- public Executor newExecutor(Transaction transaction) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return newExecutor(transaction, defaultExecutorType);
- }
- public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>executorType = executorType == null ? defaultExecutorType : executorType;
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Executor executor;
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>if (ExecutorType.BATCH == executorType) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> executor = new BatchExecutor(this, transaction);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>} else if (ExecutorType.REUSE == executorType) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> executor = new ReuseExecutor(this, transaction);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>} else {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> executor = new SimpleExecutor(this, transaction);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>if (cacheEnabled) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> executor = new CachingExecutor(executor);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>executor = (Executor) interceptorChain.pluginAll(executor);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return executor;
- }
复制代码 从上面的代码可以看到mybatis支持的拦截类型只有四种(按拦截顺序)
1.Executor 执行器接口
2.StatementHandler sql构建处理器
3.ParameterHandler 参数处理器
4.ResultSetHandler 结果集处理器
2.拦截器原理
- public class InterceptorChain {
- private final List<Interceptor> interceptors = new ArrayList<>();
- // 遍历定义的拦截器,对拦截的对象进行包装
- public Object pluginAll(Object target) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>for (Interceptor interceptor : interceptors) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> target = interceptor.plugin(target);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return target;
- }
- public void addInterceptor(Interceptor interceptor) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>interceptors.add(interceptor);
- }
- public List<Interceptor> getInterceptors() {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return Collections.unmodifiableList(interceptors);
- }
- }
- #Interceptor
- public interface Interceptor {
- Object intercept(Invocation invocation) throws Throwable;
- default Object plugin(Object target) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return Plugin.wrap(target, this);
- }
- default void setProperties(Properties properties) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>// NOP
- }
- }
复制代码 mybatis拦截器本质上使用了jdk动态代理,interceptorChain拦截器链中存储了用户定义的拦截器,会遍历进行对目标对象代理包装。
用户自定义拦截器类需要实现Interceptor接口,以及实现intercept方法,plugin和setProperties方法可重写,plugin方法一般不会改动,该方法调用了Plugin的静态方法wrap实现了对目标对象的代理- public class Plugin implements InvocationHandler {
- // 拦截目标对象
- private final Object target;
- // 拦截器对象-执行逻辑
- private final Interceptor interceptor;
- // 拦截接口和拦截方法的映射
- private final Map<Class<?>, Set<Method>> signatureMap;
- private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>this.target = target;
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>this.interceptor = interceptor;
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>this.signatureMap = signatureMap;
- }
- // 获取jdk代理对象
- public static Object wrap(Object target, Interceptor interceptor) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>// 存储拦截接口和拦截方法的映射
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Class<?> type = target.getClass();
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>// 获取拦截目标对象实现的接口,若为空则不代理
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>if (interfaces.length > 0) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> return Proxy.newProxyInstance(
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> type.getClassLoader(),
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> interfaces,
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> new Plugin(target, interceptor, signatureMap));
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return target;
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>try {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> // 获取需要拦截的方法集合,若不存在则使用目标对象执行
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> Set<Method> methods = signatureMap.get(method.getDeclaringClass());
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> if (methods != null && methods.contains(method)) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>// Invocation存储了目标对象、拦截方法以及方法参数
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return interceptor.intercept(new Invocation(target, method, args));
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> }
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> return method.invoke(target, args);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>} catch (Exception e) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> throw ExceptionUtil.unwrapThrowable(e);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- }
- private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>// 获取Intercepts注解值不能为空
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>// issue #251
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>if (interceptsAnnotation == null) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Signature[] sigs = interceptsAnnotation.value();
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>// key 拦截的类型
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>for (Signature sig : sigs) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> Set<Method> methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> try {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>// 获取拦截的方法
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Method method = sig.type().getMethod(sig.method(), sig.args());
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>methods.add(method);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> } catch (NoSuchMethodException e) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> }
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return signatureMap;
- }
- private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>Set<Class<?>> interfaces = new HashSet<>();
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>while (type != null) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> for (Class<?> c : type.getInterfaces()) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>if (signatureMap.containsKey(c)) {
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> interfaces.add(c);
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> }
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> type = type.getSuperclass();
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>}
- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>return interfaces.toArray(new Class<?>[interfaces.size()]);
- }
- }
复制代码- @Documented
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.TYPE)
- public @interface Intercepts {
- /**
- * Returns method signatures to intercept.
- *
- * @return method signatures
- */
- Signature[] value();
- }
- @Documented
- @Retention(RetentionPolicy.RUNTIME)
- @Target({})
- public @interface Signature {
- /**
- * Returns the java type.
- *
- * @return the java type
- */
- Class<?> type();
- /**
- * Returns the method name.
- *
- * @return the method name
- */
- String method();
- /**
- * Returns java types for method argument.
- * @return java types for method argument
- */
- Class<?>[] args();
- }
复制代码 可以看到,当被拦截的方法被执行时主要调用自定义拦截器的intercept方法,把拦截对象、方法以及方法参数封装成Invocation对象传递过去。
在getSignatureMap方法中可以看到,自定义的拦截器类上需要添加Intercepts注解并且Signature需要有值,Signature注解中的type为需要拦截对象的接口(Executor.class/StatementHandler/ParameterHandler/ResultSetHandler),method为需要拦截的方法的方法名,args为拦截方法的方法参数类型。
3.参考例子
接下来举一个拦截器实现对结果集下划线转驼峰的例子来简要说明这个例子拦截的是ResultSetHandler的handleResultSets方法,这个方法是用来对结果集处理的,看intercept方法首先调用了目标对象的方法接着强转为List类型,这里为什么可以强转呢,因为我们可以看到handleResultSets方法定义 List handleResultSets(Statement stmt) throws SQLException; 返回的是List类型,然后遍历列表,若元素是map类型的再进行处理把key值转化为驼峰形式重新put到map中。
最后不要忘了把自定义的拦截器添加到配置中,这边是使用xml配置的,添加完后接着运行测试代码,可以看到列user_id已经转换成驼峰形式了。- <plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>
复制代码- #mapper接口List selectAllUsers();#mapper.xml<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>select user_id, username, password, nickname<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>from user<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins><plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>#java测试类public class Test { public static void main(String[] args) throws IOException {<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) {<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> // 构建session工厂 DefaultSqlSessionFactory<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> SqlSession sqlSession = sqlSessionFactory.openSession();<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> UserMapper userMapper = sqlSession.getMapper(UserMapper.class);<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins> System.out.println(userMapper.selectAllUsers());<plugins>
- <plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">
- </plugin>
- </plugins>} }}
复制代码 
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |