Mybatis Invoker

2023-11-11 12:38
文章标签 mybatis invoker

本文主要是介绍Mybatis Invoker,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Mybatis中的Invoker对反射API中的Field.get () Fielid.get()  Method.invoke()三个方法进行了二次封装,将一些模板式的代码封装了起来,在新的版本中,还加入了安全检查。

其结构如下:

接口定义:

/*** @author Clinton Begin*/
public interface Invoker {Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;Class<?> getType();
}

接口定义较为简单,我们来看看它的实现类,先看GetFieldInvoker:

/*** @author Clinton Begin* 对field的get(获取属性值)操作进行增强,增加了强吻(private修饰的属性通过设置setAccessible方法来强行操作)机制* 之所以不用getter方法可能是为了强吻,即不提供getter方法我也可以强制访问*/
public class GetFieldInvoker implements Invoker {private final Field field;public GetFieldInvoker(Field field) {this.field = field;}@Overridepublic Object invoke(Object target, Object[] args) throws IllegalAccessException {try {return field.get(target);} catch (IllegalAccessException e) {if (Reflector.canControlMemberAccessible()) {field.setAccessible(true);return field.get(target);} else {throw e;}}}@Overridepublic Class<?> getType() {return field.getType();}

GetFiledInvoker,乍一看,还以为是操作getter方法,仔细观察发现它操作的是Field,而非 Method。一般我们自己操作Field时,遇到 private修饰的属性就需要强制访问了,GetFiledInvoker帮我们封装了这一步,而且,只有在发生IllegalAccessException 异常时才做强制访问(用private 修饰的field字段被反射操作时,会抛出此异常),这样做的好处是对于一些无需强制访问的Field,就不再需要开启强制访问,例如用public修饰的Field.

另外这里还会去检查权限的问题,如下代码:

Reflector.canControlMemberAccessible()

就是说当你有权限的时候才能去开启强制访问,否则,你没有权限也去开启强制访问,自然也是失败的。

SetFieldInvoker和GetFieldInvoker代码几乎差不多,唯一区别是一个get,一个set,这里不再赘述。

MethodInvoker:

public class MethodInvoker implements Invoker {/*** 没有调用,还不清楚作用* */private final Class<?> type;private final Method method;/*** 参数长度是是1时,type=参数的类型* 否则,type=return type* */public MethodInvoker(Method method) {this.method = method;if (method.getParameterTypes().length == 1) {type = method.getParameterTypes()[0];} else {type = method.getReturnType();}}@Overridepublic Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {try {return method.invoke(target, args);} catch (IllegalAccessException e) {if (Reflector.canControlMemberAccessible()) {method.setAccessible(true);return method.invoke(target, args);} else {throw e;}}}@Overridepublic Class<?> getType() {return type;}
}

MethodInvoker 代码和GetFileldInvoker代码逻辑差不多,区别是MethodInvoker操作的是MethodInvoker的是Method对象,那么为什么会即提供了MethodInvoker又提供了GetFileldInvoker/SetFieldInvoker呢?我的猜测是当被操作的Bean有getter/setter时,mybatis会通过MethodInvoker来调用getter/setter完成属性的get/set,当被操作Bean的属性没有提供getter/setter时,这里就需要SetFieldInvoker和GetFieldInvoker来完成对field的get/set了,带着这个疑问我们去看一下Reflector源代码:

从setMethods/getMethods的泛型定义可以看出,这两个集合实际保存的是invoker,接着:

从266和275行可以得到两条信息:

1,setMethods/getMethods的key是field name

2,只有当setMethods中不存在该字段名对应的invoker时,才会添加,那么在什么情况下不存在呢?在该field没有getter/setter时。

也就是说,当setMethods|getMethods中没有field name对应methodInvoker时,才会调用 addSetField/addGetField,我们打开其中一个方法:

286行显示add了一个SetFieldInvoker并put到了setMethods中。

AmbiguousMethodInvoker:

public class AmbiguousMethodInvoker extends MethodInvoker {private final String exceptionMessage;public AmbiguousMethodInvoker(Method method, String exceptionMessage) {super(method);this.exceptionMessage = exceptionMessage;}@Overridepublic Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {throw new ReflectionException(exceptionMessage);}

Ambiguous是有歧义的意思,从字面意思上来猜测,它是一种提高健壮性的设计,当getter/setter的方法签名相同,返回类型却不同时,初始化不会停止,有歧义的getter/setter也不会被丢弃,如果你不调用,相安无事,当你调用的时候,立马抛出异常告诉你,这个方法可能由歧义。

 

这篇关于Mybatis Invoker的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/390112

相关文章

解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

《解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题》本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常... 目录myBATis-plus-boot-starpythonter与mybatis-spring-b

Spring Boot 中整合 MyBatis-Plus详细步骤(最新推荐)

《SpringBoot中整合MyBatis-Plus详细步骤(最新推荐)》本文详细介绍了如何在SpringBoot项目中整合MyBatis-Plus,包括整合步骤、基本CRUD操作、分页查询、批... 目录一、整合步骤1. 创建 Spring Boot 项目2. 配置项目依赖3. 配置数据源4. 创建实体类

Mybatis拦截器如何实现数据权限过滤

《Mybatis拦截器如何实现数据权限过滤》本文介绍了MyBatis拦截器的使用,通过实现Interceptor接口对SQL进行处理,实现数据权限过滤功能,通过在本地线程变量中存储数据权限相关信息,并... 目录背景基础知识MyBATis 拦截器介绍代码实战总结背景现在的项目负责人去年年底离职,导致前期规

MyBatis框架实现一个简单的数据查询操作

《MyBatis框架实现一个简单的数据查询操作》本文介绍了MyBatis框架下进行数据查询操作的详细步骤,括创建实体类、编写SQL标签、配置Mapper、开启驼峰命名映射以及执行SQL语句等,感兴趣的... 基于在前面几章我们已经学习了对MyBATis进行环境配置,并利用SqlSessionFactory核

MyBatis延迟加载的处理方案

《MyBatis延迟加载的处理方案》MyBatis支持延迟加载(LazyLoading),允许在需要数据时才从数据库加载,而不是在查询结果第一次返回时就立即加载所有数据,延迟加载的核心思想是,将关联对... 目录MyBATis如何处理延迟加载?延迟加载的原理1. 开启延迟加载2. 延迟加载的配置2.1 使用

mybatis的整体架构

mybatis的整体架构分为三层: 1.基础支持层 该层包括:数据源模块、事务管理模块、缓存模块、Binding模块、反射模块、类型转换模块、日志模块、资源加载模块、解析器模块 2.核心处理层 该层包括:配置解析、参数映射、SQL解析、SQL执行、结果集映射、插件 3.接口层 该层包括:SqlSession 基础支持层 该层保护mybatis的基础模块,它们为核心处理层提供了良好的支撑。

Spring+MyBatis+jeasyui 功能树列表

java代码@EnablePaging@RequestMapping(value = "/queryFunctionList.html")@ResponseBodypublic Map<String, Object> queryFunctionList() {String parentId = "";List<FunctionDisplay> tables = query(parent

Mybatis中的like查询

<if test="templateName != null and templateName != ''">AND template_name LIKE CONCAT('%',#{templateName,jdbcType=VARCHAR},'%')</if>

JavaWeb【day09】--(Mybatis)

1. Mybatis基础操作 学习完mybatis入门后,我们继续学习mybatis基础操作。 1.1 需求 需求说明: 根据资料中提供的《tlias智能学习辅助系统》页面原型及需求,完成员工管理的需求开发。 通过分析以上的页面原型和需求,我们确定了功能列表: 查询 根据主键ID查询 条件查询 新增 更新 删除 根据主键ID删除 根据主键ID批量删除

MyBatis 切换不同的类型数据库方案

下属案例例当前结合SpringBoot 配置进行讲解。 背景: 实现一个工程里面在部署阶段支持切换不同类型数据库支持。 方案一 数据源配置 关键代码(是什么数据库,该怎么配就怎么配) spring:datasource:name: test# 使用druid数据源type: com.alibaba.druid.pool.DruidDataSource# @需要修改 数据库连接及驱动u