互联网轻量级框架SSM-查缺补漏第八天(MyBatis插件plugin使用及原理)

简言:今天进行第八天的记录(只是写了八天)。有的时候看的多,有的时候看的少,看的少的时候就攒几天一起写了。而今天这个插件我昨天写了一下午,下班没写完就回去了,今天把尾收了,再加上一个过程图方便下面原理的理解。我这个特别不爱看书的人都看半个多月了,希望我一个月真能养成个戒不掉的习惯~第八章插件在前一篇介绍了四个对象,是SqlSession执行过程中通过他们来完成数据库操作和结果返回的。(Execut...

互联网轻量级框架SSM-查缺补漏第八天(MyBatis插件plugin使用及原理)

  简言:今天进行第八天的记录(只是写了八天)。有的时候看的多,有的时候看的少,看的少的时候就攒几天一起写了。而今天这个插件我昨天写了一下午,下班没写完就回去了,今天把尾收了,再加上一个过程图方便下面原理的理解。我这个特别不爱看书的人都看半个多月了,希望我一个月真能养成个戒不掉的习惯~

第八章插件

  在前一篇介绍了四个对象,是SqlSession执行过程中通过他们来完成数据库操作和结果返回的。(ExecutorStatementHandlerParameterHandlerResultSetHandler)。我昨天的查缺补漏有记载,要是想深入了解就可以去查资料了,或者看我这本书的第七章(书名《JavaEE互联网轻量级框架整合开发》)

  插件的原理就是在四大对象调度时插入我们的代码去执行一些特殊的要求以满足特殊的场景需求

  斜体字是部分原理。我先在这插入一张流程图,如果有疑问可以看到最后再返回来琢磨一下这个图。

  使用方法:(举例:要想在预编译之前在控制台上打印一些东西,就需要拦截执行SQL的StatementHandler对象的预编译方法,也就是prepare方法)

  在MyBatis中使用插件,就必须实现interceptor接口,实现它的三个方法(代码中有注释,应该能知道啥意思):

package com.ssm.chapter8.plugin;import java.sql.Connection;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;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.reflection.SystemMetaObject;import org.apache.log4j.Logger;@Intercepts({ @Signature(type=StatementHandler.class,method="prepare",args = {Connection.class,Integer.class})})public class MyPlugin implements Interceptor { private Logger log = Logger.getLogger(MyPlugin.class); private Properties props = null; /**  * 插件方法,它代替StatementHandler的prepare方法  ** @param invocation 入参  * @return 返回预编译后的preparedStatement  * @throws Throwable 异常  * */ @Override public Object intercept(Invocation invocation) throws Throwable {  StatementHandler statementHandler = (StatementHandler)invocation.getTarget();  //进行绑定  MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);  Object object = null;  /*分离代理对象链(由于目标类可能被多个拦截器[插件]拦截,从而形成多次代理,通过循环可以分离出最原始的目标类)*/  while(metaStatementHandler.hasGetter("h")){object = metaStatementHandler.getValue("h");metaStatementHandler = SystemMetaObject.forObject(object);  }  statementHandler = (StatementHandler)object;  String sql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");  Long parameterObject = (Long)metaStatementHandler.getValue("delegate.boundSql.parameterObject"); log.info("执行的SQL:【" sql "】");  log.info("参数:【" parameterObject "】");  log.info("before......");  //如果当前代理的事一个非代理对象,那么它就会回调用真实拦截对象的方法  //如果不是,那么它就会调度下一个插件代理对象的invoke方法  Object obj = invocation.proceed();  log.info("after......");  return obj; } /**  * 生成代理对象  ** @param target 被拦截对象  * @return 代理对象  * */ public Object plugin(Object target) {  // 采用系统默认的Plugin.wrap方法生成  return Plugin.wrap(target, this); } /**  * 设置参数,MyBatis初始化时,就会生成插件实例,并调用这个方法  ** @param props 配置参数  * */ public void setProperties(Properties props) {  this.props = props;  log.info("dbType = " this.props.getProperty("dbType"));}}

  标黄的三个就是要去实现的方法:

  • intercept:英译:拦截。简单说就是拦截签名(指类名上面的注解@Signature)中对应中对应方法。参数Invocation就是被拦截内容的整合。
  • plugin:英译:插件(计算机名词)。target是被拦截的对象
  • setProperties:设置参数。这个参数是要在XML配置中配置的。

  注解@Intercepts说明它是一个拦截器。@Singnature是注册拦截器签名的地方,只有签名满足要求才能拦截,type可以是四大对象中的一个,这里是StatementHandler。method代表要拦截四大对象的某一接口方法,而args则表示该方法的参数(要根据拦截对象的方法进行拦截。)下面贴一段StatementHandler中prepare方法的定义代码。

public abstract Statement prepare(Connection connection, Integer integer) throws SQLException;

  所以args中是一个Connection.class和 Integer.class。拦截后,通过Invocation对象可以反射调度原来对象的方法。贴一段Invocation的源代码。

public class Invocation { public Invocation(Object target, Method method, Object args[]) {  this.target = target;  this.method = method;  this.args = args; } public Object getTarget() {  return target; } public Method getMethod() {  return method; } public Object[] getArgs() {  return args; } public Object proceed() throws InvocationTargetException, IllegalAccessException {  return method.invoke(target, args); } private final Object target; private final Method method; private final Object args[];}

  一看就知道Target是被拦截的目标对象,Method是被拦截的方法,Args就是注解中的参数,这里的proceed方法是通过反射调用原对象中的方法。

  配置XML:注意MyBatis配置XML中标签的顺序

<plugins><!-- 插件 --> <plugin interceptor="com.ssm.chapter8.plugin.MyPlugin">  <property name="dbType" value="mysql"/> </plugin></plugins>

  我使用的查询配置:

<select id="getRole" parameterType="Long" resultType="role"> select id,role_name as roleName,note from t_role where id = #{id}</select>

 

源文地址:https://www.guoxiongfei.cn/cntech/7270.html