1 反射工具类
Java中的反射功能虽然强大,但是代码编写起来比较复杂且容易出错。Mybatis框架提供了专门的反射包,对常用的反射操作进行了简化封装,提供了更简单方便的API给调用者进行使用,主要的反射包代码结果如下:
2 核心接口
2.1 ObjectFactory接口
MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。
2.2 ReflectorFactory接口
Mybatis使用一个 ReflectorFactory对象工厂去创建Reflector对象, 每一个Reflector对应一个java的Class类,其中包含了这个java的Class类的元信息,而 ReflectorFactory对象工厂就是用来创建并缓存Reflector对象的。
2.3 Invoker接口
Mybatis使用一个 Invoker接口来扩展java的Class类中的方法的调用执行,包含getter/setter以及其他方法和未明确方法的调用执行。
2.4 ObjectWrapper接口
ObjectWrapper 是对对象的包装的接口,抽象了对象的字段信息、 getter| setter 方法、和上面三个成员的数据类型,它定义了一系列查询对象属性信息的方法,以及更新属性的方法 。
3 核心类
3.1 Reflector类
Reflector中存储了反射需要使用的类的元信息(字节码的类型、属性、getter/setter、数据类型、构造器等等)
然后我们可以看看Reflector中提供的公共的API方法
方法名称 | 作用 |
---|---|
getType | 获取Reflector表示的Class |
getDefaultConstructor | 获取默认的构造器 |
hasDefaultConstructor | 判断是否有默认的构造器 |
getSetInvoker | 根据属性名称获取对应的Invoker 对象 |
getGetInvoker | 根据属性名称获取对应的Invoker对象 |
getSetterType | 获取属性对应的类型 比如: String name; // getSetterType(“name”) --> java.lang.String |
getGetterType | 与上面是对应的 |
getGetablePropertyNames | 获取所有的可读属性名称的集合 |
getSetablePropertyNames | 获取所有的可写属性名称的集合 |
hasSetter | 判断是否具有某个可写的属性 |
hasGetter | 判断是否具有某个可读的属性 |
findPropertyName | 根据名称查找属性 |
3.2 DefaultReflectorFactory类
Mybatis框架内置的默认的创建Reflector对象的工厂类
3.3 MetaClass类
MetaClass 则用于获取类相关的信息。
方法 | 说明 |
---|---|
静态方法 forClass(type, reflectorFactory) | 创建 MetaClass 对象 |
hasDefaultConstructor() | 判断是否有默认构造方法 |
hasGetter(name) | 判断是否有属性 name 或 name 的 getter 方法。与 MetaObject 判断类似。 |
getGetterNames() | 获取含有 getter 相关的属性名称。与 MetaObject 判断类似。 |
getGetInvoker(name) | name 的 getter 方法的 Invoker。 |
hasSetter(name) | 判断是否有属性 name 或 name 的 setter 方法。与 MetaObject 判断类似。 |
getSetterNames() | 获取含有 setter 相关的属性名称。与 MetaObject 判断类似。 |
getSetterType(name) | 获取 setter 方法的参数类型。与 MetaObject 判断类似。 |
getSetInvoker(name) | name 的 setter 方法的 Invoker。 |
3.4 MetaObject类
MetaObject 用于获取和设置对象的属性值
方法 | 说明 |
---|---|
hasGetter(name) | 判断是否有属性 name 或 name 的 getter 方法。 1. 若定义 userId,没定义 getUserId() 方法,hasGetter(“userId”) 则返回 true; 2. 若定义方法 getUserId1(),没定义属性 userId1,hasGetter(“userId1”) 则返回 true。 |
getGetterNames() | 获取含有 getter 相关的属性名称。 1. 若定义 userId,没定义 getUserId() 方法,则 userId 会被返回; 2. 若定义方法 getUserId1(),没定义属性 userId1, 则 userId1 会被返回。 |
getGetterType(name) | 获取 getter 方法的返回类型。 |
getValue(name) | 获取属性值。 |
hasSetter(name) | 判断是否有属性 name 或 name 的 setter 方法。 1. 若定义 userId,没定义 setUserId(userId) 方法,hasSetter(“userId”) 则返回 true; 2. 若定义方法 setUserId1(userId1),没定义属性 userId1,hasSetter(“userId1”) 则返回 true。 |
getSetterNames() | 获取含有 setter 相关的属性名称。 1. 若定义 userId,没定义 setUserId(userId) 方法,则 userId 会被返回; 2. 若定义方法 setUserId1(userId1),没定义属性 userId1, 则 userId1 会被返回。 |
getSetterType(name) | 获取 setter 方法的参数类型。 |
setValue(name,value) | 设置属性值。 |
3.5 SystemMetaObject类
/**
* @author Clinton Begin
* 系统元对象
*/
public final class SystemMetaObject {
/** 默认对象工厂 */
public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
/** 默认对象包装工厂 */
public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
/** 默认空元对象 */
public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(new NullObject(), DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
private SystemMetaObject() {
// Prevent Instantiation of Static Class
}
private static class NullObject {
}
public static MetaObject forObject(Object object) {
return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
}
}
MapperMethod、 BaseExecutor、 CachingExecutor、 DefaultResultSetHandler、 DefaultParameterHandler、Configuration中都是用MetaObject类
4 使用演示
Mybatis框架的源码中提供了丰富的测试案例演示反射工具中核心的工具类的使用方式, 下面我们简单演示几个,更多测试案例可以到源码中自行查看。
4.1 Reflector使用示例
class ReflectorTest {
@Test
void testGetSetterType() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Section.class);
Assertions.assertEquals(Long.class, reflector.getSetterType("id"));
}
@Test
void testGetGetterType() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Section.class);
Assertions.assertEquals(Long.class, reflector.getGetterType("id"));
}
@Test
void shouldNotGetClass() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(Section.class);
Assertions.assertFalse(reflector.hasGetter("class"));
}
interface Entity<T> {
T getId();
void setId(T id);
}
static abstract class AbstractEntity implements Entity<Long> {
private Long id;
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
}
static class Section extends AbstractEntity implements Entity<Long> {
}
}
4.2 MetaClass使用示例
/*
* Copyright 2009-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.reflection;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.domain.misc.RichType;
import org.apache.ibatis.domain.misc.generics.GenericConcrete;
import org.junit.jupiter.api.Test;
class MetaClassTest {
@Test
void shouldTestDataTypeOfGenericMethod() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(GenericConcrete.class, reflectorFactory);
assertEquals(Long.class, meta.getGetterType("id"));
assertEquals(Long.class, meta.getSetterType("id"));
}
@Test
void shouldThrowReflectionExceptionGetGetterType() {
try {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
meta.getGetterType("aString");
org.junit.jupiter.api.Assertions.fail("should have thrown ReflectionException");
} catch (ReflectionException expected) {
assertEquals("There is no getter for property named \'aString\' in \'class org.apache.ibatis.domain.misc.RichType\'", expected.getMessage());
}
}
@Test
void shouldCheckGetterExistance() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
assertTrue(meta.hasGetter("richField"));
assertTrue(meta.hasGetter("richProperty"));
assertTrue(meta.hasGetter("richList"));
assertTrue(meta.hasGetter("richMap"));
assertTrue(meta.hasGetter("richList[0]"));
assertTrue(meta.hasGetter("richType"));
assertTrue(meta.hasGetter("richType.richField"));
assertTrue(meta.hasGetter("richType.richProperty"));
assertTrue(meta.hasGetter("richType.richList"));
assertTrue(meta.hasGetter("richType.richMap"));
assertTrue(meta.hasGetter("richType.richList[0]"));
assertEquals("richType.richProperty", meta.findProperty("richType.richProperty", false));
assertFalse(meta.hasGetter("[0]"));
}
@Test
void shouldCheckSetterExistance() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
assertTrue(meta.hasSetter("richField"));
assertTrue(meta.hasSetter("richProperty"));
assertTrue(meta.hasSetter("richList"));
assertTrue(meta.hasSetter("richMap"));
assertTrue(meta.hasSetter("richList[0]"));
assertTrue(meta.hasSetter("richType"));
assertTrue(meta.hasSetter("richType.richField"));
assertTrue(meta.hasSetter("richType.richProperty"));
assertTrue(meta.hasSetter("richType.richList"));
assertTrue(meta.hasSetter("richType.richMap"));
assertTrue(meta.hasSetter("richType.richList[0]"));
assertFalse(meta.hasSetter("[0]"));
}
@Test
void shouldCheckTypeForEachGetter() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
assertEquals(String.class, meta.getGetterType("richField"));
assertEquals(String.class, meta.getGetterType("richProperty"));
assertEquals(List.class, meta.getGetterType("richList"));
assertEquals(Map.class, meta.getGetterType("richMap"));
assertEquals(List.class, meta.getGetterType("richList[0]"));
assertEquals(RichType.class, meta.getGetterType("richType"));
assertEquals(String.class, meta.getGetterType("richType.richField"));
assertEquals(String.class, meta.getGetterType("richType.richProperty"));
assertEquals(List.class, meta.getGetterType("richType.richList"));
assertEquals(Map.class, meta.getGetterType("richType.richMap"));
assertEquals(List.class, meta.getGetterType("richType.richList[0]"));
}
@Test
void shouldCheckTypeForEachSetter() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
assertEquals(String.class, meta.getSetterType("richField"));
assertEquals(String.class, meta.getSetterType("richProperty"));
assertEquals(List.class, meta.getSetterType("richList"));
assertEquals(Map.class, meta.getSetterType("richMap"));
assertEquals(List.class, meta.getSetterType("richList[0]"));
assertEquals(RichType.class, meta.getSetterType("richType"));
assertEquals(String.class, meta.getSetterType("richType.richField"));
assertEquals(String.class, meta.getSetterType("richType.richProperty"));
assertEquals(List.class, meta.getSetterType("richType.richList"));
assertEquals(Map.class, meta.getSetterType("richType.richMap"));
assertEquals(List.class, meta.getSetterType("richType.richList[0]"));
}
@Test
void shouldCheckGetterAndSetterNames() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
assertEquals(5, meta.getGetterNames().length);
assertEquals(5, meta.getSetterNames().length);
}
@Test
void shouldFindPropertyName() {
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
assertEquals("richField", meta.findProperty("RICHfield"));
}
}
4.3 MetaObject使用示例
/*
* Copyright 2009-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.reflection;
import static org.junit.jupiter.api.Assertions.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.domain.blog.Author;
import org.apache.ibatis.domain.blog.Section;
import org.apache.ibatis.domain.misc.CustomBeanWrapper;
import org.apache.ibatis.domain.misc.CustomBeanWrapperFactory;
import org.apache.ibatis.domain.misc.RichType;
import org.junit.jupiter.api.Test;
class MetaObjectTest {
@Test
void shouldGetAndSetField() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richField", "foo");
assertEquals("foo", meta.getValue("richField"));
}
@Test
void shouldGetAndSetNestedField() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richType.richField", "foo");
assertEquals("foo", meta.getValue("richType.richField"));
}
@Test
void shouldGetAndSetProperty() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richProperty", "foo");
assertEquals("foo", meta.getValue("richProperty"));
}
@Test
void shouldGetAndSetNestedProperty() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richType.richProperty", "foo");
assertEquals("foo", meta.getValue("richType.richProperty"));
}
@Test
void shouldGetAndSetMapPair() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richMap.key", "foo");
assertEquals("foo", meta.getValue("richMap.key"));
}
@Test
void shouldGetAndSetMapPairUsingArraySyntax() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richMap[key]", "foo");
assertEquals("foo", meta.getValue("richMap[key]"));
}
@Test
void shouldGetAndSetNestedMapPair() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richType.richMap.key", "foo");
assertEquals("foo", meta.getValue("richType.richMap.key"));
}
@Test
void shouldGetAndSetNestedMapPairUsingArraySyntax() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richType.richMap[key]", "foo");
assertEquals("foo", meta.getValue("richType.richMap[key]"));
}
@Test
void shouldGetAndSetListItem() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richList[0]", "foo");
assertEquals("foo", meta.getValue("richList[0]"));
}
@Test
void shouldGetAndSetNestedListItem() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richType.richList[0]", "foo");
assertEquals("foo", meta.getValue("richType.richList[0]"));
}
@Test
void shouldGetReadablePropertyNames() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
String[] readables = meta.getGetterNames();
assertEquals(5, readables.length);
for (String readable : readables) {
assertTrue(meta.hasGetter(readable));
assertTrue(meta.hasGetter("richType." + readable));
}
assertTrue(meta.hasGetter("richType"));
}
@Test
void shouldGetWriteablePropertyNames() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
String[] writeables = meta.getSetterNames();
assertEquals(5, writeables.length);
for (String writeable : writeables) {
assertTrue(meta.hasSetter(writeable));
assertTrue(meta.hasSetter("richType." + writeable));
}
assertTrue(meta.hasSetter("richType"));
}
@Test
void shouldSetPropertyOfNullNestedProperty() {
MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
richWithNull.setValue("richType.richProperty", "foo");
assertEquals("foo", richWithNull.getValue("richType.richProperty"));
}
@Test
void shouldSetPropertyOfNullNestedPropertyWithNull() {
MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
richWithNull.setValue("richType.richProperty", null);
assertNull(richWithNull.getValue("richType.richProperty"));
}
@Test
void shouldGetPropertyOfNullNestedProperty() {
MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
assertNull(richWithNull.getValue("richType.richProperty"));
}
@Test
void shouldVerifyHasReadablePropertiesReturnedByGetReadablePropertyNames() {
MetaObject object = SystemMetaObject.forObject(new Author());
for (String readable : object.getGetterNames()) {
assertTrue(object.hasGetter(readable));
}
}
@Test
void shouldVerifyHasWriteablePropertiesReturnedByGetWriteablePropertyNames() {
MetaObject object = SystemMetaObject.forObject(new Author());
for (String writeable : object.getSetterNames()) {
assertTrue(object.hasSetter(writeable));
}
}
@Test
void shouldSetAndGetProperties() {
MetaObject object = SystemMetaObject.forObject(new Author());
object.setValue("email", "test");
assertEquals("test", object.getValue("email"));
}
@Test
void shouldVerifyPropertyTypes() {
MetaObject object = SystemMetaObject.forObject(new Author());
assertEquals(6, object.getSetterNames().length);
assertEquals(int.class, object.getGetterType("id"));
assertEquals(String.class, object.getGetterType("username"));
assertEquals(String.class, object.getGetterType("password"));
assertEquals(String.class, object.getGetterType("email"));
assertEquals(String.class, object.getGetterType("bio"));
assertEquals(Section.class, object.getGetterType("favouriteSection"));
}
@Test
void shouldDemonstrateDeeplyNestedMapProperties() {
HashMap<String, String> map = new HashMap<>();
MetaObject metaMap = SystemMetaObject.forObject(map);
assertTrue(metaMap.hasSetter("id"));
assertTrue(metaMap.hasSetter("name.first"));
assertTrue(metaMap.hasSetter("address.street"));
assertFalse(metaMap.hasGetter("id"));
assertFalse(metaMap.hasGetter("name.first"));
assertFalse(metaMap.hasGetter("address.street"));
metaMap.setValue("id", "100");
metaMap.setValue("name.first", "Clinton");
metaMap.setValue("name.last", "Begin");
metaMap.setValue("address.street", "1 Some Street");
metaMap.setValue("address.city", "This City");
metaMap.setValue("address.province", "A Province");
metaMap.setValue("address.postal_code", "1A3 4B6");
assertTrue(metaMap.hasGetter("id"));
assertTrue(metaMap.hasGetter("name.first"));
assertTrue(metaMap.hasGetter("address.street"));
assertEquals(3, metaMap.getGetterNames().length);
assertEquals(3, metaMap.getSetterNames().length);
@SuppressWarnings("unchecked")
Map<String,String> name = (Map<String,String>) metaMap.getValue("name");
@SuppressWarnings("unchecked")
Map<String,String> address = (Map<String,String>) metaMap.getValue("address");
assertEquals("Clinton", name.get("first"));
assertEquals("1 Some Street", address.get("street"));
}
@Test
void shouldDemonstrateNullValueInMap() {
HashMap<String, String> map = new HashMap<>();
MetaObject metaMap = SystemMetaObject.forObject(map);
assertFalse(metaMap.hasGetter("phone.home"));
metaMap.setValue("phone", null);
assertTrue(metaMap.hasGetter("phone"));
// hasGetter returns true if the parent exists and is null.
assertTrue(metaMap.hasGetter("phone.home"));
assertTrue(metaMap.hasGetter("phone.home.ext"));
assertNull(metaMap.getValue("phone"));
assertNull(metaMap.getValue("phone.home"));
assertNull(metaMap.getValue("phone.home.ext"));
metaMap.setValue("phone.office", "789");
assertFalse(metaMap.hasGetter("phone.home"));
assertFalse(metaMap.hasGetter("phone.home.ext"));
assertEquals("789", metaMap.getValue("phone.office"));
assertNotNull(metaMap.getValue("phone"));
assertNull(metaMap.getValue("phone.home"));
}
@Test
void shouldNotUseObjectWrapperFactoryByDefault() {
MetaObject meta = SystemMetaObject.forObject(new Author());
assertTrue(!meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));
}
@Test
void shouldUseObjectWrapperFactoryWhenSet() {
MetaObject meta = MetaObject.forObject(new Author(), SystemMetaObject.DEFAULT_OBJECT_FACTORY, new CustomBeanWrapperFactory(), new DefaultReflectorFactory());
assertEquals(CustomBeanWrapper.class, meta.getObjectWrapper().getClass());
// Make sure the old default factory is in place and still works
meta = SystemMetaObject.forObject(new Author());
assertNotEquals(CustomBeanWrapper.class, meta.getObjectWrapper().getClass());
}
@Test
void shouldMethodHasGetterReturnTrueWhenListElementSet() {
List<Object> param1 = new ArrayList<>();
param1.add("firstParam");
param1.add(222);
param1.add(new Date());
Map<String, Object> parametersEmulation = new HashMap<>();
parametersEmulation.put("param1", param1);
parametersEmulation.put("filterParams", param1);
MetaObject meta = SystemMetaObject.forObject(parametersEmulation);
assertEquals(param1.get(0), meta.getValue("filterParams[0]"));
assertEquals(param1.get(1), meta.getValue("filterParams[1]"));
assertEquals(param1.get(2), meta.getValue("filterParams[2]"));
assertTrue(meta.hasGetter("filterParams[0]"));
assertTrue(meta.hasGetter("filterParams[1]"));
assertTrue(meta.hasGetter("filterParams[2]"));
}
}
5、反射工具类在Mybatis框架中的应用
5.1 DefaultResultSetHandler
查询结果集的核心处理方法createResultObject()中有很多地方都使用了到了反射工具类
5.2 DefaultParameterHandler
/**
* 替换SQL语句中的占位符为实际传入的参数值的方法
*/
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
// 从BoundSql对象中获取到参数映射对象集合
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
// 依次取出parameterMapping对象
ParameterMapping parameterMapping = parameterMappings.get(i);
// 保证当前处理的parameterMapping对象都是输入参数
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
// 获取当前处理的parameterMapping对象的属性名称
String propertyName = parameterMapping.getProperty();
// 如果BoundSql对象的附加参数对象中包含该属性名称, 直接从BoundSql对象的附加参数对象中获取到该属性KEY对应的值
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
// 如果ParameterObject为空,说明没有传值,值直接就为null
} else if (parameterObject == null) {
value = null;
// 如果类型注册器中有该参数对象对应的类型处理器,则该参数取值就是parameterObject
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
// 以上都不满足,就创建一个元数据对象,然后从元数据对象汇总通过属性获取到对应的取值
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// 获取当前parameterMapping对象的类型处理器
TypeHandler typeHandler = parameterMapping.getTypeHandler();
// 获取当前parameterMapping对象的JDBC数据类型
JdbcType jdbcType = parameterMapping.getJdbcType();
// 如果参数输入值为null并且数据库数据类型为null,就将jdbcType类型设置为OTHER类型
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 为什么这里是使用i + 1?
// insert into t_user(name, age, gender, email) value(?, ?, ?, ?)
// 因为解析出来的带占位的sql语法中的?参数的计数是从1开始的, 不是从0开始的
// 调用typeHandler的替换参数的方法替换到SQL语句中目标位置上占位符上为输入的参数值
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
5.3 Configuration
反射在java项目的实践应用中是非常重要的,必须熟练掌握,很多成熟的开源框架中都已经封装了很多非常好的反射工具,我们在进行源码阅读时,可以将这些精华的部分进行搜集整理应用到自己的项目中,只看是学不会的,编程这个东西还是更注重实践,实践的多了,自然你就会自主的去学习和思考了。