项目概况

第14篇:Mybatis中反射工具

2026-01-292 min read后端技术
Mybatis

!!! tip 我们知道在java中基于反射的速度相对来说是很慢的, 但是如果对反射信息加了缓存性能可以提升1半以上, 如果在对反射设置了忽略安全检查, 性能更是会再提升1半。那么这个时候 反射带来的性能问题基本可以忽略了。在Mybatis中关于反射的工具就可以很大程度来解决这个问题。本篇讲解下Mybatis中的工具类, 以后在项目中也可以直接使用。 !!!

一、反射缓存类 Reflector

所有的反射对象都会被生成一个 Reflector, Reflector 会把反射的方法、构造、字段、类型等信息都缓存起来。这样的设计主要是为了解决性能问题。

java
1public class Reflector { 2 3 private final Class<?> type; 4 private final String[] readablePropertyNames; 5 private final String[] writablePropertyNames; 6 private final Map<String, Invoker> setMethods = new HashMap<>(); 7 private final Map<String, Invoker> getMethods = new HashMap<>(); 8 private final Map<String, Class<?>> setTypes = new HashMap<>(); 9 private final Map<String, Class<?>> getTypes = new HashMap<>(); 10 private Constructor<?> defaultConstructor; 11 12 private Map<String, String> caseInsensitivePropertyMap = new HashMap<>(); 13 14}

ReflectorFactory 反射工厂用来缓存反射对象 Reflector

java
1 2public class DefaultReflectorFactory implements ReflectorFactory { 3 private boolean classCacheEnabled = true; 4 private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>(); 5 6 @Override 7 public Reflector findForClass(Class<?> type) { 8 if (classCacheEnabled) { 9 // synchronized (type) removed see issue #461 10 return MapUtil.computeIfAbsent(reflectorMap, type, Reflector::new); 11 } else { 12 return new Reflector(type); 13 } 14 } 15 16}

二、通过反射操作对象 MetaObject

MetaObject 从名字来看就是对对象进行操作,他的操作都是通过反射来进行的。

2.1 简单对象操作

java
1 @AllArgsConstructor 2 @ToString 3 public static class Person { 4 5 @Getter(AccessLevel.PRIVATE) 6 @Setter(AccessLevel.PRIVATE) 7 private String name; 8 9 @Getter(AccessLevel.PRIVATE) 10 @Setter(AccessLevel.PRIVATE) 11 private int age; 12 13 @Getter(AccessLevel.PRIVATE) 14 @Setter(AccessLevel.PRIVATE) 15 private Long userId; 16 } 17 18 /** 19 * 通过反射给对象赋值 20 */ 21 @Test 22 public void metaObjectTest() { 23 Person jay = new Person("周杰伦", 40, 1L); 24 MetaObject jayMetaObject = MetaObject.forObject(jay, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory()); 25 if (jayMetaObject.hasGetter("name")) { 26 Class<?> name = jayMetaObject.getGetterType("name"); 27 // class java.lang.String 28 System.out.println(name); 29 jayMetaObject.setValue("name", "昆凌"); 30 // 昆凌 31 System.out.println(jayMetaObject.getValue("name")); 32 } 33 // 昆凌 34 System.out.println(jay.getName()); 35 }

2.2 嵌套对象操作

java
1 @AllArgsConstructor 2 @ToString 3 public static class Person { 4 5 @Getter(AccessLevel.PRIVATE) 6 @Setter(AccessLevel.PRIVATE) 7 private String name; 8 9 @Getter(AccessLevel.PRIVATE) 10 @Setter(AccessLevel.PRIVATE) 11 private int age; 12 13 @Getter(AccessLevel.PRIVATE) 14 @Setter(AccessLevel.PRIVATE) 15 private Long userId; 16 } 17 18 @AllArgsConstructor 19 @ToString 20 public static class School { 21 22 @Getter(AccessLevel.PRIVATE) 23 @Setter(AccessLevel.PRIVATE) 24 private String name; 25 26 @Getter(AccessLevel.PRIVATE) 27 @Setter(AccessLevel.PRIVATE) 28 private Person person; 29 } 30 31 @Test 32 public void fillChildObjectTest() { 33 School school = new School("西天大学", new Person("周杰伦", 40, 1L)); 34 MetaObject schoolMetaObject = MetaObject.forObject(school, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory()); 35 // 周杰伦 36 System.out.println(schoolMetaObject.getValue("person.name")); 37 schoolMetaObject.setValue("person.name", "昆凌"); 38 // 昆凌 39 System.out.println(school.getPerson().getName()); 40 }

三、获取反射信息 MetaClass

MetaClass 主要是对 Reflector信息的一个包装并提供些更高级的操作。如跟嵌套类赋值

java
1 @Test 2 public void metaClassTest() throws Exception { 3 MetaClass metaClass = MetaClass.forClass(School.class, new DefaultReflectorFactory()); 4 // class com.test.tool.MetaObjectTest$Person 5 System.out.println(metaClass.getGetterType("person")); 6 7 School school = new School(); 8 Invoker setNameInvoker = metaClass.getSetInvoker("name"); 9 // 通过反射给空对象赋值 10 setNameInvoker.invoke(school, new Object[]{"Jay"}); 11 12 // 通过反射获取空对象 13 Invoker getNameInvoker = metaClass.getGetInvoker("name"); 14 // Jay 15 System.out.println(getNameInvoker.invoke(school, new Object[]{})); 16 }