mybatis插件原理_idea插件库

mybatis插件原理_idea插件库Mybatis插件插件简介一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展。这样的好处是显而易见的,一是增加了框架的灵活性。二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作。以MyBatis为例,我们可基于MyBatis插件机制实现分页、分表,监控等功能。由于插件和业务无关,业务也无法感知插件的存在。因此可以无感植入插件,在无形中增强功能Mybatis插件介绍Mybatis作为一个应用广泛的优秀的ORM开源框架,这个框架具有强大的灵活性,在四大组件(Executo

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

Mybatis插件

插件简介

一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展。这样的好处是显而易见的,一是增加了框架的灵活性。二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作。以MyBatis为例,我们可基于MyBatis插件机制实现分页、分表,监控等功能。由于插件和业务 无关,业务也无法感知插件的存在。因此可以无感植入插件,在无形中增强功能

Mybatis插件介绍

Mybatis作为一个应用广泛的优秀的ORM开源框架,这个框架具有强大的灵活性,在四大组件(Executor、StatementHandler、ParameterHandler、ResultSetHandler)处提供了简单易用的插 件扩展机制。Mybatis对持久层的操作就是借助于四大核心对象。MyBatis支持用插件对四大核心对象进行拦截,对mybatis来说插件就是拦截器,用来增强核心对象的功能,增强功能本质上是借助于底层的动态代理实现的,换句话说,MyBatis中的四大对象都是代理对象
在这里插入图片描述
MyBatis所允许拦截的方法如下:

  1. 执行器Executor (update、query、commit、rollback等方法);
  2. SQL语法构建器StatementHandler (prepare、parameterize、batch、updates query等方 法);
  3. 参数处理器ParameterHandler (getParameterObject、setParameters方法);
  4. 结果集处理器ResultSetHandler (handleResultSets、handleOutputParameters等方法);

Mybatis插件原理

在四大对象创建的时候:
5. 每个创建出来的对象不是直接返回的,而是interceptorChain.pluginAll(parameterHandler);
6. 获取到所有的Interceptor (拦截器)(插件需要实现的接口);调用 interceptor.plugin(target);返回 target 包装后的对象
7. 插件机制,我们可以使用插件为目标对象创建一个代理对象;AOP (面向切面)我们的插件可以为四大对象创建出代理对象,代理对象就可以拦截到四大对象的每一个执行;

拦截

插件具体是如何拦截并附加额外的功能的呢?以ParameterHandler来说

public ParameterHandler newParameterHandler(MappedStatement mappedStatement,Object object, BoundSql sql, InterceptorChain interceptorChain){ 
   
	ParameterHandler parameterHandler =
	mappedStatement.getLang().createParameterHandler(mappedStatement,object,sql);
	parameterHandler = (ParameterHandler)
	interceptorChain.pluginAll(parameterHandler);
	return parameterHandler;
}
public Object pluginAll(Object target) { 
   
	for (Interceptor interceptor : interceptors) { 
   
		target = interceptor.plugin(target);
	}
	return target;
}

interceptorChain保存了所有的拦截器(interceptors),是mybatis初始化的时候创建的。调用拦截器链中的拦截器依次的对目标进行拦截或增强。interceptor.plugin(target)中的target就可以理解为mybatis中的四大对象。返回的target是被重重代理后的对象
如果我们想要拦截Executor的query方法,那么可以这样定义插件:

@Intercepts({ 
   
	@Signature(
	type = Executor.class,
	method = "query",
	args=
	{ 
   MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class}
	)
})
public class ExeunplePlugin implements Interceptor { 
   
//省略逻辑
}

除此之外,我们还需将插件配置到sqlMapConfig.xm l中。

<plugins>
	<plugin interceptor="com.lagou.plugin.ExamplePlugin">
	</plugin>
</plugins>

这样MyBatis在启动时可以加载插件,并保存插件实例到相关对象(InterceptorChain,拦截器链) 中。待准备工作做完后,MyBatis处于就绪状态。我们在执行SQL时,需要先通过DefaultSqlSessionFactory 创建 SqlSession。Executor 实例会在创建 SqlSession 的过程中被创建, Executor实例创建完毕后,MyBatis会通过JDK动态代理为实例生成代理类。这样,插件逻辑即可在 Executor相关方法被调用前执行。

自定义插件

插件接口

Mybatis 插件接口-Interceptor
8. Intercept方法,插件的核心方法
9. plugin方法,生成target的代理对象
10. setProperties方法,传递插件所需参数

自定义插件

设计实现一个自定义插件

@Intercepts ({ 
   //注意看这个大花括号,也就这说这里可以定义多个@Signature对多个地方拦截,都用这个拦截器
	@Signature (type = StatementHandler .class , //这是指拦截哪个接口
	method = "prepare"//这个接口内的哪个方法名,不要拼错了
	args = { 
    Connection.class, Integer .class}), 这是拦截的方法的入参,按顺序写到这,不要多也不要少,如果方法重载,可是要通过方法名和入参来确定唯一的
	})
public class MyPlugin implements Interceptor { 
   
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	// //这里是每次执行操作的时候,都会进行这个拦截器的方法内
	Override
	public Object intercept(Invocation invocation) throws Throwable { 
   
	//增强逻辑
		System.out.println("对方法进行了增强....")return invocation.proceed(); //执行原方法
	}
	/** * //主要是为了把这个拦截器生成一个代理放到拦截器链中 * ^Description包装目标对象 为目标对象创建代理对象 * @Param target为要拦截的对象 * @Return代理对象 */
	Override
	public Object plugin(Object target) { 
   
		System.out.println("将要包装的目标对象:"+target);
		return Plugin.wrap(target,this);
	}
	/**获取配置文件的属性**/
	//插件初始化的时候调用,也只调用一次,插件配置的属性从这里设置进来
	Override
	public void setProperties(Properties properties) { 
   
		System.out.println("插件配置的初始化参数:"+properties );
	}
}

sqlMapConfig.xml

<plugins>
	<plugin interceptor="com.lagou.plugin.MySqlPagingPlugin">
		<!--配置参数-->
		<property name="name" value="Bob"/>
	</plugin>
</plugins>

源码分析

Plugin实现了 InvocationHandler接口,因此它的invoke方法会拦截所有的方法调用。invoke方法会 对所拦截的方法进行检测,以决定是否执行插件逻辑。该方法的逻辑如下:

// -Plugin
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
   
	try { 
   
		/* *获取被拦截方法列表,比如: * signatureMap.get(Executor.class), 可能返回 [query, update, commit] */
		Set<Method> methods = signatureMap.get(method.getDeclaringClass());
		//检测方法列表是否包含被拦截的方法
		if (methods != null && methods.contains(method)){ 
   
			//执行插件逻辑
			return interceptor.intercept(new Invocation(target, method,args));
		}
		//执行被拦截的方法
		return method.invoke(target, args);
	} catch(Exception e){ 
   
	}
}

invoke方法的代码比较少,逻辑不难理解。首先,invoke方法会检测被拦截方法是否配置在插件的@Signature注解中,若是,则执行插件逻辑,否则执行被拦截方法。插件逻辑封装在intercept中,该方法的参数类型为Invocationo Invocation主要用于存储目标类,方法以及方法参数列表。下面简单看一下该类的定义

public class Invocation { 
   
private final Object target;
private final Method method;
private final Object[] args;
public Invocation(Object targetf Method method, Object[] args) { 
   
this.target = target;
this.method = method;
//省略部分代码
public Object proceed() throws InvocationTargetException, IllegalAccessException
{ 
    //调用被拦截的方法
>> 

关于插件的执行逻辑就分析结束

pageHelper分页插件

MyBati s可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤:

导入通用PageHelper的坐标
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>
在mybatis核心配置文件中配置PageHelper插件
<!--注意:分页助手的插件 配置在通用馆mapper之前*-->*
<plugin interceptor="com.github.pagehelper.PageHelper">
<!—指定方言 >
<property name="dialect" value="mysql"/>
</plugin>
测试分页代码实现
@Test
public void testPageHelper() { 
   
	//设置分页参数
	PageHelper.startPage(1, 2);
	List<User> select = userMapper2.select(null);
	for (User user : select) { 
   
		System.out.println(user);
	}
}
获得分页相关的其他参数
PageInfo<User> pageInfo = new PageInfo<User>(select);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo. getPages ());
System.out.println("当前页:"+pageInfo. getPageNum());
System.out.println("每页显万长度:"+pageInfo.getPageSize());
System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/184961.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • pycharm2018设置中文界面_pycharm界面

    pycharm2018设置中文界面_pycharm界面pycharm中文版界面设置:(推荐学习:python视频教程)jJ1少儿编程网-Scratch_Python_教程_免费儿童编程学习平台1、找到pycharm的文件安装位置jJ1少儿编程网-Scratch_Python_教程_免费儿童编程学习平台jJ1少儿编程网-Scratch_Python_教程_免费儿童编程学习平台2、找到语言文件应安装的文件夹jJ1少儿编程网-Scratch_Python_…

    2022年8月25日
    5
  • vs2008 sp1怎么安装_vs2003

    vs2008 sp1怎么安装_vs2003vs2005的英文版sp1补丁431M中文版补丁sp1已经集成了VS2005WebApplicationProject VS2005的SP1足有430M,快有VS2003SP1的三倍大了!而且,安装起来是同样的慢,慢得让人以为是不是装不下去了(噢,我现在正在安装……)。  简单看了看VisualStudio2005ServicePack1说明:  1、支持新处理器(

    2022年10月5日
    0
  • 真正解决Jenkins安装插件总是报错的问题(二)

    真正解决Jenkins安装插件总是报错的问题(二)

    2021年8月31日
    56
  • 乱码_idea控制台中文乱码解决不了

    乱码_idea控制台中文乱码解决不了IntelliJIDEA如果不进行配置的话,运行程序时控制台中文乱码问题会非常严重,甚至影响我们对信息的获取和程序的跟踪。通过历年的开发经验,在本文中我总结出四点用于解决控制台中文乱码问题的方法,希望有助于大家。

    2025年6月12日
    14
  • Eurake和Zookeeper的区别

    Eurake和Zookeeper的区别拉取方式zookeeper通知消费者来拿Eurake是定时去拿集群方式zookeeper分主从eureka没有主从之分设计角度不同capc 一致性 a 可用性 p 分区容错区 如果zookeeper的主集群挂掉之后那么整个zookeeper的集群就无法对外提供服务,大多数情况可以容忍一段时间的脏数据但是不能接收整个注册中心无法对外提供服务。所以在设计时zookeeper强调cp(c在官网的解释是一致性,底层有一个queu…

    2022年5月27日
    67
  • C++编程工具(java常用工具)

    给c++程序员的一份礼物-常用工具集■…开发环境  —->Turboc  DOS时代c语言开发的经典工具,目前适合两类人使用:c语言beginner(尤其是学生一族),具有怀旧情节的专业人士:)  —->VisualC++6.0/7.0  稳定而强大的IDE开发环境,具有丰富的调试功能,定制宏的功能也是其一大特色。Microsoft的经典之作,功能强大自不必言说

    2022年4月13日
    44

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号