前言
上次讲了mybatis 中Mapper注入spring源码分析,实质就是如何将一个接口放入Spring
工厂中,有放就有取,因此这次介绍的是mybatis是如何从Spring
工厂中取出相应的Mapper
。
源码分析
MapperRegistry
:以Mapper.class
为key,MapperProxyFactory
对象为value,对外用于生产Mapper接口对应的代理对象。
MapperProxyFactory
:作用生产对应的Mapper代理。
MapperProxy
:实现了InvocationHandler
接口,代理类。
MapperFactoryBean
:获得代理对象,将其提供给Spring
。
现在我们以上图为标准,从MapperFactoryBean
开始一一分析源码。
MapperFactoryBean
其实在上一节已经提示过,这个类很重要。
image.png
以下是MapperFactoryBean
的源码,其实代码还是比较简单的,不过这个类是连接Spring
和mybatis
的桥梁,Spring
通过调用这个类的getObject()
方法实例化代理对象,然后将其注入到Mapper上。
// 这是一个FactoryBean类
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
public MapperFactoryBean() {
}
//Spring实例化这个类,就是通过这个构造函数,mapperInterface 就是Mapper接口的class对象
// 参数就是上一张截图中的xxxxx.addGenericArgumentValue(xxxxx)
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
/**
* {@inheritDoc}
*/
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
//configuration 底层调用MapperRegistry类将mapperInterface保存起来,以便调用
//getObject() 方法的时候能够获取Mapper接口对应的代理类。
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
}
}
/**
* 获取Mapper接口对应的代理类对象,后面依赖Mapper接口注入的对象就是这个代理对象。
这个方法的调用是在AbstractBeanFactory对象里面。具体到方法是getObjectForBeanInstance
**/
@Override
public T getObject() throws Exception {
// 生成代理对象的调用链路
// SqlSession -->Configuration-->MapperRegistry-->MapperProxyFactory->MapperProxy
return getSqlSession().getMapper(this.mapperInterface);
}
@Override
public Class<T> getObjectType() {
return this.mapperInterface;
}
@Override
public boolean isSingleton() {
return true;
}
}
DefaultSqlSession
public class DefaultSqlSession implements SqlSession{
private final Configuration configuration;
....
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
...
}
Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
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);
}
}
MapperProxyFactory
两个newInstance
方法都是生成代理对象。
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
MapperProxy
了解下Java的动态代理就知道了。
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
// 执行sql 操作。
return mapperMethod.execute(sqlSession, args);
}
}
总结
这节本质就是动态代理+FactoryBean实现接口代理能够依赖注入。理论将了两节,下一节将动手实现接口放入spring
工厂,以及能够依赖注入。
网友评论