引子
接口如何反射生成一个实现了它各种方法的对象?
//一定生成了一个实现UserDao接口的对象,然后向上转型,通过接口访问了!
UserDao userMapper = sqlSession.getMapper(UserDao.class);
可以看到没个sqlSession都要新建userMapper类,好处是不会产生并发问题,坏处是消耗资源。所以连接数必须得控制呀!
DefaultSqlSession.class
//返回一个泛型对象,UserDao.class
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
Configuration.class
由configuration来为当前session创建向上转型的实现了User.Dao接口的对象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
//configuration的mapperRegistry对象为什么具有这个功能呢?
}
MapperRegistry.class
这是一个注册类,知道所有T接口的对象的动态代理的工厂类。
没有工厂类的话就先创建一个工厂,然后再new一个代理对象。
//这是一个map<type,typeProxyFactory>,存放已知的对于数据库的映射:ORM对象和关系的映射
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory =//从map里取出对应的由动态代理生成的代理工厂!
(MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {//如果代理工厂不存在,那就没啥好说的了!
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {//存在的话就尝试让代理工厂给当前sqlSession产生一个实例,咋产生的呢?看下面
try {
return mapperProxyFactory.newInstance(sqlSession);//让代理工厂给当前sqlSession产生一个代理对象
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
MapperProxyFactory.class
这就是代理类的工厂,为当前session产生一个代理对象的方法。
private final Class<T> mapperInterface;
public T newInstance(SqlSession sqlSession) {
//创建一个代理对象
MapperProxy<T> mapperProxy =
new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);//调用下面的方法
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(
this.mapperInterface.getClassLoader(),//目标对象类加载器
new Class[]{this.mapperInterface}, //目标对象接口
mapperProxy);//代理对象
}