mybatis学习十(源码分析-反射模块)

目录

一、引入

二、mybatis反射核心API

2.1  ObjectFactory

2.2  ReflectorFactory

2.3  ObjectWrapper

2.4  MetaObject

2.5  举例


一、引入

反射可谓是mybatis中重要的一块,那么在mybatis中如果使用反射的呢?

我们使用JDBC为例

public class JdbcDemo {
	static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
	static final String DB_URL = "jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true";
	static final String USER = "root";
	static final String PASS = "root";

	@Test
	public void QueryStatementDemo() {
		Connection conn = null;
		Statement stmt = null;
		List<TUser> users = new ArrayList<>();
		try {
			// STEP 2: 注册mysql的驱动
			Class.forName("com.mysql.jdbc.Driver");

			// STEP 3: 获得一个连接
			System.out.println("Connecting to database...");
			conn = DriverManager.getConnection(DB_URL, USER, PASS);

			// STEP 4: 创建一个查询
			System.out.println("Creating statement...");
			stmt = conn.createStatement();
			String userName = "lison";
			String sql="SELECT * FROM t_user where user_name='"+userName+"'";
			ResultSet rs = stmt.executeQuery(sql);
			
			// STEP 5: 从resultSet中获取数据并转化成bean
			while (rs.next()) {
				System.out.println("------------------------------");
				// Retrieve by column name
				TUser user = new TUser();
				user.setId(rs.getInt("id"));
				user.setUserName(rs.getString("user_name"));
				user.setSex(rs.getByte("sex"));
				user.setMobile(rs.getString("mobile"));
				user.setEmail(rs.getString("email"));
				user.setNote(rs.getString("note"));

				System.out.println(user.toString());
				
				users.add(user);
			}
			// STEP 6: 关闭连接
			rs.close();
			stmt.close();
			conn.close();
		} catch (SQLException se) {
			// Handle errors for JDBC
			se.printStackTrace();
		} catch (Exception e) {
			// Handle errors for Class.forName
			e.printStackTrace();
		} finally {
			// finally block used to close resources
			try {
				if (stmt != null)
					stmt.close();
			} catch (SQLException se2) {
			}// nothing we can do
			try {
				if (conn != null)
					conn.close();
			} catch (SQLException se) {
				se.printStackTrace();
			}
		}
	}
}

我们上述JDBC示例中,可以概括查询数据库分为如下四步

  1. 从数据库中查询到数据
  2. 找到数据库表字段与对象属性之间的映射关系
  3. 创建目标对象
  4. 属性赋值

在JDBC中,2)3)4)步都是我们手动进行的,我们手动创建对象,我们知道表字段和对象属性之间的映射关系,我们直接就可以给对象的属性赋值

但是在mybatis中,这些是如何实现的呢?

二、mybatis反射核心API

  1. 1)ObjectFactory:MyBatis每次创建结果对象的新实例时,它都会使用对象工厂(ObjectFactory)去构建POJO
  2. 2)ReflectorFactory:创建Reflector的工厂类,Reflector是mybatis反射模块的基础,每个Reflector对象都对应一个类,在其中缓存了反射操作所需要的类元信息
  3. 3)ObjectWrapper:对对象的包装,抽象了对象的属性信息,他定义了一系列查询对象属性信息的方法,以及更新属性的方法
  4. 4)ObjectWrapperFactory: ObjectWrapper 的工厂类,用于创建ObjectWrapper

2.1  ObjectFactory

ObjectFactory是一个接口,定义了构建POJO的方法。

//使用构造函数通过反射实例化对象
public interface ObjectFactory {
  void setProperties(Properties properties);
  <T> T create(Class<T> type);
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
  <T> boolean isCollection(Class<T> type);
}

常用的实现类有DefaultObjectFactory,以下是部分源码

public class DefaultObjectFactory implements ObjectFactory, Serializable {

    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) {
....
}
}

在DefaultObjectFactory类中,就是通过构造函数的方式反射创建对象

至此,解决了对象创建的问题,那么属性赋值该如何解决呢?

难点:mybatis不知道对象有哪些属性

解决:ReflectorFactory接口中定义封装了类的元信息

2.2  ReflectorFactory

ReflectorFactory是创建Reflector的工厂类,而Reflector是mybatis反射模块的基础,每个Reflector对象都对应一个类,在其中缓存了反射操作所需要的类元信息

public interface ReflectorFactory {
  boolean isClassCacheEnabled();
  void setClassCacheEnabled(boolean classCacheEnabled);
  Reflector findForClass(Class<?> type);
}

常用实现类DefaultReflectorFactory

public class DefaultReflectorFactory implements ReflectorFactory {
  private boolean classCacheEnabled = true;
  private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
  //....省略构造函数等

  @Override
  public Reflector findForClass(Class<?> type) {
    if (classCacheEnabled) {
       return reflectorMap.computeIfAbsent(type, Reflector::new);
    } else {
      return new Reflector(type);
    }
  }
}

主要作用:解析类的class信息并缓存起来

这里,我们可以关注一下Reflector,它才是真正对应一个类,缓存了反射操作所需要的类元信息,部分源码

public class Reflector {

  private final Class<?> type;//对应的class
  private final String[] readablePropertyNames;//可读属性的名称集合,存在get方法即可读
  private final String[] writeablePropertyNames;//可写属性的名称集合,存在set方法即可写
  private final Map<String, Invoker> setMethods = new HashMap<>();//保存属性相关的set方法
  private final Map<String, Invoker> getMethods = new HashMap<>();//保存属性相关的get方法
  private final Map<String, Class<?>> setTypes = new HashMap<>();//保存属性相关的set方法入参类型
  private final Map<String, Class<?>> getTypes = new HashMap<>();//保存属性相关的get方法返回类型
  private Constructor<?> defaultConstructor;//class默认的构造函数

  //记录所有属性的名称集合
  private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
   ......

}

2.3  ObjectWrapper

这里封装了对象的信息,定义了一系列查询对象属性信息的方法,以及更新属性的方法。最重要的是可以动态的给属性赋值

//这样对象也有了,类的信息也有了,解决对象属性赋值的问题
public class BeanWrapper extends BaseWrapper {

  private final Object object;   //反射创建的对象

  private final MetaClass metaClass;   //封装了类信息的Reflector
  .....
}

2.4  MetaObject

从2.4可以看出关于反射有很多辅助类,但是mybatis做了统一封装,便于我们使用

MetaObject:封装了对象元信息,包装了mybatis中五个核心的反射类。也是提供给外部使用的反射工具类,

可以利用它可以读取或者修改对象的属性信息

类图如下

2.5  举例

public void reflectionTest(){
				
		//反射工具类初始化
		ObjectFactory objectFactory = new DefaultObjectFactory();
		TUser user = objectFactory.create(TUser.class);
		ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
		ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
		MetaObject metaObject = MetaObject.forObject(user, objectFactory, objectWrapperFactory, reflectorFactory);
		
		//模拟数据库行数据转化成对象
		//1.模拟从数据库读取数据
		Map<String, Object> dbResult = new HashMap<>();
		dbResult.put("id", 1);
		dbResult.put("user_name", "zc");
		dbResult.put("real_name", "左");
		TPosition tp = new TPosition();
		tp.setId(1);
		dbResult.put("position_id", tp);
		//2.模拟映射关系
		Map<String, String> mapper = new HashMap<String, String>();
		mapper.put("id", "id");
		mapper.put("userName", "user_name");
		mapper.put("realName", "real_name");
		mapper.put("position", "position_id");
		
		//3.使用反射工具类将行数据转换成pojo
		BeanWrapper objectWrapper = (BeanWrapper) metaObject.getObjectWrapper();
		Set<Entry<String, String>> entrySet = mapper.entrySet();
		for (Entry<String, String> colInfo : entrySet) {
			String propName = colInfo.getKey();
			Object propValue = dbResult.get(colInfo.getValue());
			PropertyTokenizer proTokenizer = new PropertyTokenizer(propName);
			objectWrapper.set(proTokenizer, propValue);
		}
		System.out.println(metaObject.getOriginalObject());
	}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值