以下完整示例请参考 mybatis 源码:https://github.com/RononoaZoro/customize-mybatis (我学习的时候抄的源码)
本文从以下几个方面介绍:
- 1、反射简介
- 2、Java 中反射机制 Api
- 3、Mybatis 中对反射的应用
1、反射简介
1.1、反射机制定义
-
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改其本身状态或行为的一种能力。
-
在 Java 环境中,反射机制允许程序在执行时获取某个类自身的定义信息,如属性和方法等,也可以实现动态创建类的对象、变更属性的内容或执行特定的方法的功能。从而使 Java 具有动态语言的特性,增强了程序的灵活性和可移植性。
1.2、反射机制的作用
- 1)、在运行时判断任意一个对象所属的类型。
- 2)、在运行时构造任意一个类的对象。
- 3)、在运行时判断任意一个类所具有的成员变量和方法。
- 4)、在运行时调用任意一个对象的方法,甚至可以调用private方法。
- 5)、注意:上述功能都是在运行时环境中,而不是在编译时环境中。
2、Java 中反射机制 Api
实现Java反射机制的 API 在 Java.lang.reflect 包下,以下是一些重要的类:
- 1)、Class 类:描述类的信息
- 2)、Filed 类:描述属性的信息
- 3)、Method 类:描述方法的信息
- 4)、Constructor 类:描述构造方法的信息
- 5)、Array 类:提供了动态创建数组及访问数组元素的静态方法。该类中的所有方法都是静态的。
3、Mybatis 中对反射的应用
3.1、利用反射创建默认对象
3.1.1、ObjectFactory
对象工厂接口
package com.luo.ibatis.reflection.factory;
import java.util.List;
import java.util.Properties;
/**
* @author :archer
* @date :Created in 2021/6/15 15:38
* @description:对象工厂接口
* MyBatis uses an ObjectFactory to create all needed new Objects.
* @modified By:
*/
public interface ObjectFactory {
/**
* Sets configuration properties.
* 设置属性值
* @param properties configuration properties
*/
void setProperties(Properties properties);
/**
* Creates a new object with default constructor.
* 使用默认构造方法创建对象
* @param type Object type
* @return
*/
<T> T create(Class<T> type);
/**
* Creates a new object with the specified constructor and params.
* 使用特定的构造方法创建对象
* @param type Object type
* @param constructorArgTypes Constructor argument types
* @param constructorArgs Constructor argument values
* @return
*/
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
/**
* Returns true if this object can have a set of other objects.
* It's main purpose is to support non-java.util.Collection objects like Scala collections.
* 判断是否是集合
* 它的主要目的是支持非 java.util.Collection 对象,如 Scala 集合。
* @param type Object type
* @return whether it is a collection or not
* @since 3.1.0
*/
<T> boolean isCollection(Class<T> type);
}
3.1.2、DefaultObjectFactory
默认工厂实现类
- 主要提供创建一些默认的接口实现(如 List 接口是 ArrayList)
/**
* Copyright 2009-2018 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 com.luo.ibatis.reflection.factory;
import com.luo.ibatis.reflection.ReflectionException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.*;
/**
* @author :archer
* @date :Created in 2021/6/15 15:38
* @description:默认对象工厂类
* @modified By:
*/
public class DefaultObjectFactory implements ObjectFactory, Serializable {
private static final long serialVersionUID = -8855120656740914948L;
@Override
public <T> T create(Class<T> type) {
return create(type, null, null);
}
@SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
Class<?> classToCreate = resolveInterface(type);
// we know types are assignable(可转让的)
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
@Override
public void setProperties(Properties properties) {
// no props for default
}
/**
* 实例化
* @param type
* @param constructorArgTypes
* @param constructorArgs
* @param <T>
* @return
*/
private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor<T> constructor;
if (constructorArgTypes == null || constructorArgs == null) {
constructor = type.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance();
}
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} catch (Exception e) {
StringBuilder argTypes = new StringBuilder();
if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
for (Class<?> argType : constructorArgTypes) {
argTypes.append(argType.getSimpleName());
argTypes.append(",");
}
argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing(逗号) ,
}
StringBuilder argValues = new StringBuilder();
if (constructorArgs != null && !constructorArgs.isEmpty()) {
for (Object argValue : constructorArgs) {
argValues.append(String.valueOf(argValue));
argValues.append(",");
}
argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
}
throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
}
}
/**
* 接口解析
* @param type
* @return
*/
protected Class<?> resolveInterface(Class<?> type) {
Class<?> classToCreate;
if (type == List.class || type == Collection.class || type == Iterable.class) {
classToCreate = ArrayList.class;
} else if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) {
// issue #510 Collections Support
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
return classToCreate;
}
@Override
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
}
3.1.3、示例
TestClass
package com.luo.ibatis.reflection.factory;
/**
* TestClass
*
* @author Ryan Lamore
*/
public class TestClass {
String myString;
Integer myInteger;
public TestClass(String myString, Integer myInteger) {
this.myString = myString;
this.myInteger = myInteger;
}
}
DefaultObjectFactoryTest
public class DefaultObjectFactoryTest {
@Test
public void createClass() throws Exception {
DefaultObjectFactory defaultObjectFactory = new DefaultObjectFactory();
TestClass testClass = defaultObjectFactory.create(TestClass.class,
Arrays.<Class<?>>asList(String.class, Integer.class), Arrays.<Object>asList("foo", 0));
Assert.assertEquals("myInteger didn't match expected", (Integer) 0, testClass.myInteger);
Assert.assertEquals("myString didn't match expected", "foo", testClass.myString);
}
@Test
public void createArrayList() throws Exception {
DefaultObjectFactory defaultObjectFactory = new DefaultObjectFactory();
List list = defaultObjectFactory.create(List.class);
Assert.assertTrue(" list should be ArrayList", list instanceof ArrayList);
Collection collection = defaultObjectFactory.create(Collection.class);
Assert.assertTrue(" collection should be ArrayList", collection instanceof ArrayList);
Iterable iterable = defaultObjectFactory.create(Iterable.class);
Assert.assertTrue(" iterable should be ArrayList", iterable instanceof ArrayList);
}
}
3.2、利用反射描述类信息
3.2.1、ReflectorFactory
- 反射工厂接口
- 缓存以及生成描述类信息的 Reflector 实例
package com.luo.ibatis.reflection;
/**
* @author :archer
* @date :Created in 2021/6/11 17:42
* @description:反射工厂接口
* @modified By:
*/
public interface ReflectorFactory {
boolean isClassCacheEnabled();
void setClassCacheEnabled(boolean classCacheEnabled);
Reflector findForClass(Class<?> type);
}
3.2.2、DefaultReflectorFactory
- ReflectorFactory 的默认实现
package com.luo.ibatis.reflection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @author :archer
* @date :Created in 2021/6/11 17:53
* @description:默认反射工厂类
* @modified By:
*/
public class DefaultReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();
public DefaultReflectorFactory() {
}
@Override
public boolean isClassCacheEnabled() {
return classCacheEnabled;
}
@Override
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}
@Override
public Reflector findForClass(Class<?> type) {
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
Reflector cached = reflectorMap.get(type);
if (cached == null) {
cached = new Reflector(type);
reflectorMap.put(type, cached);
}
return cached;
} else {
return new Reflector(type);
}
}
}
3.2.3、Reflector
- mybatis 反射体系核心类:描述类信息的类
package com.luo.ibatis.reflection;
import com.luo.ibatis.reflection.invoker.GetFieldInvoker;
import com.luo.ibatis.reflection.invoker.Invoker;
import com.luo.ibatis.reflection.invoker.MethodInvoker;
import com.luo.ibatis.reflection.invoker.SetFieldInvoker;
import com.luo.ibatis.reflection.property.PropertyNamer;
import java.lang.reflect.*;
import java.util.*;
/**
* @author :archer
* @date :Created in 2021/6/11 17:43
* @description:反射执行器
* @modified By:
*/
public class Reflector {
private final Class<?> type;
private final String[] readablePropertyNames;
private final String[] writeablePropertyNames;
private final Map<String, Invoker> setMethods = new HashMap<String, Invoker>();
private final Map<String, Invoker> getMethods = new HashMap<String, Invoker>();
private final Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>();
private final Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>();
private Constructor<?> defaultConstructor;
private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>();
public Reflector(Class<?> clazz) {
type = clazz;
addDefaultConstructor(clazz);
addGetMethods(clazz);
addSetMethods(clazz);
addFields(clazz);
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
private void addDefaultConstructor(Class<?> clazz) {
Constructor<?>[] consts = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : consts) {
if (constructor.getParameterTypes().length == 0) {
if (canControlMemberAccessible()) {
try {
constructor.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
if (constructor.isAccessible()) {
this.defaultConstructor = constructor;
}
}
}
}
private void addGetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
Method[] methods = getClassMethods(cls);
for (Method method : methods) {
if (method.getParameterTypes().length > 0) {
continue;
}
String name = method.getName();
if ((name.startsWith("get") && name.length() > 3)
|| (name.startsWith("is") && name.length() > 2)) {
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingGetters, name, method);
}
}
resolveGetterConflicts(conflictingGetters);
}
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
for