Mybatis系列二十:插件开发

 MyBatis在四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制一层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果。
 MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。
 默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
  Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  ParameterHandler (getParameterObject, setParameters)
  ResultSetHandler (handleResultSets, handleOutputParameters)
  StatementHandler (prepare, parameterize, batch, update, query)
一、插件原理:
  在四大对象创建的时候
  1、每个创建出来的对象不是直接返回的,而是
   interceptorChain.pluginAll(parameterHandler);

	public Object pluginAll(Object target) {
	    for (Interceptor interceptor : interceptors) {
	      target = interceptor.plugin(target);
	    }
	    return target;
	  }

  2、获取到所有的Interceptor(拦截器)(插件需要实现的接口);
    调用interceptor.plugin(target);返回target包装后的对象
  3、插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP(面向切面)
    我们的插件可以为四大对象创建出代理对象;
    代理对象就可以拦截到四大对象的每一个执行;
在这里插入图片描述
二、编写插件
1、编写插件实现Interceptor接口,并使用 @Intercepts注解完成插件签名

/**
 * 完成插件签名:
 *	  告诉MyBatis当前插件用来拦截哪个对象的哪个方法。
 *	  type:要拦截的四大对象的哪个对象。
 *	  method:要拦截对象的	哪个方法。
 *	  args:要拦截的方法的参数。
 */
@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());
		//动态的改变一下sql运行的参数:以前1号员工,实际从数据库查询3号员工
		Object target = invocation.getTarget();
		System.out.println("当前拦截到的对象:"+target);
		//拿到:StatementHandler==>ParameterHandler===>parameterObject
		//拿到target的元数据
		MetaObject metaObject = SystemMetaObject.forObject(target);
		Object value = metaObject.getValue("parameterHandler.parameterObject");
		System.out.println("sql语句用的参数是:"+value);
		//修改完sql语句要用的参数
		metaObject.setValue("parameterHandler.parameterObject", 11);
		//执行目标方法
		Object proceed = invocation.proceed();
		//返回执行后的返回值
		return proceed;
	}

	/**
	 * plugin:
	 * 		包装目标对象的:包装:为目标对象创建一个代理对象
	 */
	@Override
	public Object plugin(Object target) {
		// TODO Auto-generated method stub
		//我们可以借助Plugin的wrap方法来使用当前Interceptor包装我们目标对象
		System.out.println("MyFirstPlugin...plugin:mybatis将要包装的对象"+target);
		Object wrap = Plugin.wrap(target, this);
		//返回为当前target创建的动态代理
		return wrap;
	}

	/**
	 * setProperties:
	 * 		将插件注册时的property属性设置进来
	 */
	@Override
	public void setProperties(Properties properties) {
		// TODO Auto-generated method stub
		System.out.println("插件配置的信息:"+properties);
	}

}
@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
	}

}

2、在全局配置文件中注册插件

<!-- 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>

测试:

@Test
public void test() throws IOException {
	String resource = "mybatis-config.xml";
	InputStream inputStream = Resources.getResourceAsStream(resource);
	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

	SqlSession openSession = sqlSessionFactory.openSession();
	try {
		EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
		Employee employee = mapper.getEmpById(1);
		System.out.println(mapper);
		System.out.println(employee);
	} finally {
		openSession.close();
	}
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值