Dullonjiang 2020-01-23
运行流程:
/** * 1、获取sqlSessionFactory对象: * 解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession; * 注意:【MappedStatement】:代表一个增删改查的详细信息 * * 2、获取sqlSession对象 * 返回一个DefaultSQlSession对象,包含Executor和Configuration; * 这一步会创建Executor对象; * * 3、获取接口的代理对象(MapperProxy) * getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象 * 代理对象里面包含了,DefaultSqlSession(Executor) * 4、执行增删改查方法 * * 总结: * 1、根据配置文件(全局,sql映射)初始化出Configuration对象 * 2、创建一个DefaultSqlSession对象, * 他里面包含Configuration以及 * Executor(根据全局配置文件中的defaultExecutorType创建出对应的Executor) * 3、DefaultSqlSession.getMapper():拿到Mapper接口对应的MapperProxy; * 4、MapperProxy里面有(DefaultSqlSession); * 5、执行增删改查方法: * 1)、调用DefaultSqlSession的增删改查(Executor); * 2)、会创建一个StatementHandler对象。 * (同时也会创建出ParameterHandler和ResultSetHandler) * 3)、调用StatementHandler预编译参数以及设置参数值; * 使用ParameterHandler来给sql设置参数 * 4)、调用StatementHandler的增删改查方法; * 5)、ResultSetHandler封装结果 * 注意: * 四大对象每个创建的时候都有一个interceptorChain.pluginAll(parameterHandler); */
首先要在mybatis全局配置文件中配置:
<!--plugins:注册插件 --> <plugins> <plugin interceptor="com.gong.mybatis.dao.MyFirstPlugin"> <property name="username" value="root"/> <property name="password" value="123456"/> </plugin> </plugins>
property为自定义的属性名和值。
MyFirstPlugin.java
package com.gong.mybatis.dao; import java.util.Properties; import org.apache.ibatis.executor.statement.StatementHandler; 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=StatementHandler.class,method="parameterize",args=java.sql.Statement.class) }) public class MyFirstPlugin implements Interceptor { /** * intercept:拦截 * */ @Override public Object intercept(Invocation invocation) throws Throwable { // TODO Auto-generated method stub System.out.println("myfirstplugin...intercept:"+invocation.getMethod()); //执行目标方法 Object proceed = invocation.proceed(); //返回执行后的返回值 return proceed; } //包装目标对象,为目标对象创建一个代理对象 @Override public Object plugin(Object target) { System.out.println("-->myfirstplugin...plugin,将要包装的对象:"+target); // TODO Auto-generated method stub Object wrap = Plugin.wrap(target, this); //返回为当前target创建的动态代理 return wrap; } //将插件注册时的property属性设置进来 @Override public void setProperties(Properties properties) { // TODO Auto-generated method stub System.out.println("插件配置的信息:"+properties); } }
我们进行测试:随便运行一个要测试的方法
package com.gong.mybatis.test; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.gong.mybatis.bean.Department; import com.gong.mybatis.bean.Employee; import com.gong.mybatis.dao.EmployeeMapper; import com.gong.mybatis.mapper.EmployeeMapperDynamicSql; public class TestMybatis5 { public SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream is = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(is); } @Test public void test() throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try { EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee em = mapper.getEmpById(1); System.out.println(em); } finally { // TODO: handle finally clause openSession.close(); } } }
输出:
插件配置的信息:{password=123456, username=root} -->myfirstplugin...plugin,将要包装的对象: -->myfirstplugin...plugin,将要包装的对象:3da5 -->myfirstplugin...plugin,将要包装的对象:4973 -->myfirstplugin...plugin,将要包装的对象:65367 DEBUG 01-23 12:59:28,739 ==> Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? (BaseJdbcLogger.java:145) myfirstplugin...intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException DEBUG 01-23 12:59:28,823 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 01-23 12:59:28,850 <== Total: 1 (BaseJdbcLogger.java:145) Employee [id=1, lastName=dema, gender=1, email, dept=null]
说明:执行sql方法时会调用四大对象,如果不是自己配置拦截的类型,就放过,否则就进行拦截。我们定义的插件是拦截StatementHandler类中的parameterize方法,其参数为java.sql.Statement。
当有多个插件时是怎么运行的?
<!--plugins:注册插件 --> <plugins> <plugin interceptor="com.atguigu.mybatis.dao.MyFirstPlugin"> <property name="username" value="root"/> <property name="password" value="123456"/> </plugin> <plugin interceptor="com.atguigu.mybatis.dao.MySecondPlugin"></plugin> </plugins>
MySecondPlugin.java
package com.gong.mybatis.dao; import java.util.Properties; import org.apache.ibatis.executor.statement.StatementHandler; 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=StatementHandler.class,method="parameterize",args=java.sql.Statement.class) }) public class MySecondPlugin implements Interceptor{ @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println("MySecondPlugin...intercept:"+invocation.getMethod()); return invocation.proceed(); } @Override public Object plugin(Object target) { // TODO Auto-generated method stub System.out.println("MySecondPlugin...plugin,要包装的对象:"+target); return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // TODO Auto-generated method stub } }
结果:
插件配置的信息:{password=123456, username=root} -->myfirstplugin...plugin,将要包装的对象: MySecondPlugin...plugin,要包装的对象: -->myfirstplugin...plugin,将要包装的对象:3da5 MySecondPlugin...plugin,要包装的对象:3da5 -->myfirstplugin...plugin,将要包装的对象:4973 MySecondPlugin...plugin,要包装的对象:4973 -->myfirstplugin...plugin,将要包装的对象:65367 MySecondPlugin...plugin,要包装的对象:65367 DEBUG 01-23 13:21:17,640 ==> Preparing: select id,last_name lastName,email,gender from tbl_employee where id = ? (BaseJdbcLogger.java:145) MySecondPlugin...intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException myfirstplugin...intercept:public abstract void org.apache.ibatis.executor.statement.StatementHandler.parameterize(java.sql.Statement) throws java.sql.SQLException DEBUG 01-23 13:21:17,698 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 01-23 13:21:17,731 <== Total: 1 (BaseJdbcLogger.java:145) Employee [id=1, lastName=dema, gender=1, email, dept=null]
需要注意一点:插件会按配置的顺序依次拦截,但在执行时会先执行后配置的,因为相当于为第一个代理对象再进行代理。