MyBatis的Configuration配置中有一个Plugin配置,根据其名可以解释为“插件”,这个插件实质可以理解为“拦截器”。“拦截器”这个名词不陌生,在众多框架中均有“拦截器”。这个Plugin有什么用呢?活着说拦截器有什么用呢?可以想想拦截器是怎么实现的。Plugin用到了Java中很重要的一个特性——动态代理。所以这个Plugin可以理解为,在调用一个方法时,我“拦截”其方法做一些我想让它做的事。它可以拦截以下方法:
在官方文档中有这么一句话:If you attempt to modify or override the behaviour of a given method, you’re likely to break the core of MyBatis. 谨慎使用自定义Plugin拦截器,因为它可能修改Mybatis核心的东西。实现自定义Plugin我们需要实现 Interceptor接口。并未这个类注解@Intercepts。
1 package day_8_mybatis.util;
2
3 import java.util.Iterator;
4 import java.util.Map;
5 import java.util.Properties;
6
7 import org.apache.ibatis.plugin.Interceptor;
8 import org.apache.ibatis.plugin.Intercepts;
9 import org.apache.ibatis.plugin.Invocation;
10 import org.apache.ibatis.plugin.Plugin;
11 import org.apache.ibatis.plugin.Signature;
12
13 /**
14 * @author turbo
15 *
16 * 2016年10月25日
17 */
18 @Intercepts({
19 @Signature(
20 type = Map.class,
21 method = "get",
22 args = {Object.class}
23 )})
24 public class ExamplePlugin implements Interceptor {
25
26 /* 此方法用于实现拦截逻辑
27 * @see org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin.Invocation)
28 */
29 @Override
30 public Object intercept(Invocation invocation) throws Throwable {
31
32 return "ExamplePlugin";
33 }
34
35 /* 使用当前的这个拦截器实现对目标对象的代理(内部实现时Java的动态代理)
36 * @see org.apache.ibatis.plugin.Interceptor#plugin(java.lang.Object)
37 */
38 @Override
39 public Object plugin(Object target) {
40 return Plugin.wrap(target, this);
41 }
42
43 /* 此方法和上一节所讲的自定义对象工厂中的setProperties一样,初始化Configuration时通过配置文件配置property传递参数给此方法并调用。
44 * @see org.apache.ibatis.plugin.Interceptor#setProperties(java.util.Properties)
45 */
46 @Override
47 public void setProperties(Properties properties) {
48 Iterator iterator = properties.keySet().iterator();
49 while (iterator.hasNext()){
50 String keyValue = String.valueOf(iterator.next());
51 System.out.println(properties.getProperty(keyValue));
52 }
53 }
54
55 }
别忘了在mybatis-config.xml的配置文件中注册自定义Plugin。(下面的配置中有一些遗留代码,是在上两节中的配置,可以选择性的忽略。)
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE configuration
3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
4 "http://mybatis.org/dtd/mybatis-3-config.dtd">
5
6 <configuration>
7 <!-- 注意configuration中各个属性配置的顺序应为:properties,settings,typeAliases,typeHandlers,objectFactory,objectWrapperFactory,reflectorFactory,plugins,environments,databaseIdProvider,mappers)-->
8 <properties>
9 <property name="driver" value="com.mysql.jdbc.Driver"/>
10 <property name="url" value="jdbc:mysql://localhost:3306/test"/>
11 <property name="username" value="root"/>
12 <property name="password" value="0000"/>
13 </properties>
14 <!--
15 <typeHandlers>
16 <typeHandler handler="day_8_mybatis.util.ExampleTypeHandler" javaType="java.util.Date" jdbcType="VARCHAR"/>
17 </typeHandlers>
18 <objectFactory type="day_8_mybatis.util.ExampleObjectFactory">
19 <property name="someProperty" value="100"/>
20 </objectFactory>
21 -->
22 <plugins>
23 <plugin interceptor="day_8_mybatis.util.ExamplePlugin">
24 <property name="someProperty" value="100"/>
25 </plugin>
26 </plugins>
27 <environments default="development">
28 <environment id="development">
29 <transactionManager type="JDBC" />
30 <dataSource type="POOLED">
31 <property name="driver" value="${driver}"/>
32 <property name="url" value="${url}"/>
33 <property name="username" value="${username}"/>
34 <property name="password" value="${password}"/>
35 </dataSource>
36 </environment>
37 </environments>
38 <mappers>
39 <mapper resource="day_8_mybatis/mapper/UserMapper.xml"/>
40 <mapper resource="day_8_mybatis/mapper/NoteMapper.xml"/>
41 </mappers>
42
43 </configuration>
44
45
客户端测试代码:
1 package day_8_mybatis;
2
3 import java.io.IOException;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import org.apache.ibatis.session.SqlSession;
8
9 import day_8_mybatis.util.ExamplePlugin;
10 import day_8_mybatis.util.SessionFactory;
11
12 /**
13 * 客户端
14 * @author turbo
15 *
16 * 2016年10月25日
17 */
18 public class Main {
19
20 /**
21 * @param args
22 * @throws IOException
23 */
24 public static void main(String[] args) throws Exception {
25 String resource = "day_8_mybatis/mybatis-config.xml"; //获取mybatis配置文件路径
26 SqlSession sqlSession = SessionFactory.getSqlSession(resource); //通过SessionFactory工具类(此工具类为自己构造即util包中的SessionFactory)构造SqlSession
27
28 Map map = new HashMap();
29 map = (Map)new ExamplePlugin().plugin(map);
30 System.out.println(map.get(""));
31
32 }
33
34 }
至此,我们就简单的了解了MyBatis中的Plugin。有兴趣的可以看看我们在客户端测试代码中的第29行所调用的plugin方法。即调用了Plugin类的静态方法wrap(Object target, Interceptor intercpetor),追踪该方法会发现,此方法即是Java的动态代理。
1 public static Object wrap(Object target, Interceptor interceptor)
2 {
3 Map signatureMap = getSignatureMap(interceptor);
4 Class type = target.getClass();
5 Class interfaces[] = getAllInterfaces(type, signatureMap);
6 if(interfaces.length > 0)
7 return Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); //返回代理类实例
8 else
9 return target;
10 }
动态代理很重要,反射很重要。一定要反复理解领会动态代理以及反射,这对我们读懂很多框架源代码有很大帮助。这篇仅仅简单了解,不做过多的深入。