赞
踩
在通过MyBatis
操作数据库之前我们一定先通过Session
对象获取指定Mappper
接口的代理对象。如下代码所示:
public class UserMapper{
@Select(value="SELECT * FROM user")
public List<User> findAll();
}
public static void main(String [] args){
Configuration configuration = new Configuration();
configuration.addMapper(UserMapper.class);
SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
// 获取SqlSession对象
try(SqlSession sqlSession = sqlSessionFactory.openSession();){
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.findAll();
}catch(Exception e){
//TODO 异常信息
}
}
1.DefaultSqlSession.调用getMapper方法 -> 2.Configuration.调用getMapper方法 -> 3.MapperRegistry调用getMapper方法 | | |-------------------------------------------------------------------------------------| | | |-->4.判断knownMappers缓存是否已经解析过指定的Mapper接口,没解析过抛错(在调用addMapper方法时就将接口添加到缓存中并对接口中的方法进行解析).解析过创建代理对象 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (Objects.isNull(mapperProxyFactory)){ throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } } | | |--> 5.创建代理对象,MapperProxy实现了InvocationHandler接口,使用JDK动态代理创建 public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } protected T newInstance(MapperProxy<T> mapperProxy) { // 用JDK自带的动态代理生成映射器 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy); }
注意第5代逻辑:
// 已解析过的Mapper接口及对应的代理工厂缓存 private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>(); public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (Objects.isNull(mapperProxyFactory)) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
先从缓存中获取接口对应的代理工厂,并判断是否存储代理工厂。不存在时抛错,表示此接口没有注册过无法创建代理对象.
何时向缓存中添加接口及对应的代理工厂呢?如下代码:
public <T> void addMapper(Class<T> type) { // mapper必须是接口!才会添加 if (type.isInterface()) { if ( knownMappers.containsKey((type)) { // 如果重复添加了,报错 throw new BindingException("Type " + type + " is already known to the MapperRegistry."); } boolean loadCompleted = false; try { // 将mapper接口放入缓存并为其创建独立的mapper接口代理对象工厂 // 每个Mapper接口有一个独立的代理工厂 knownMappers.put(type, new MapperProxyFactory<T>(type)); // 在运行分析器之前添加类型非常重要 // 否则,绑定可能会由 // 映射器解析器。如果类型已知,则不会尝试。 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); // 解析mapper接口及相应的mapper.xml文件 parser.parse(); loadCompleted = true; } finally { // 如果加载过程中出现异常需要再将这个mapper从mybatis中删除,这种方式比较丑陋吧,难道是不得已而为之? if (!loadCompleted) { knownMappers.remove(type); } } } }
在注册Mapper
接口时,会向缓存中添加接口对应的代理工厂,以便后面通过接口获取代理对象调用方法。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。