【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
引言
在 mybatis-spring 中,我们会使用 MapperFactoryBean 为我们 的mapper(interface)创建代理类。 SqlSessionFactoryBean 通过dataSource成属性创建对应的sqlSessionFactory。两个接口都实现了Spring FactoryBean interface。所以我们就通过这个来理解一下 Spring FactoryBean.
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
FactoryBean
Customizing instantiation logic with a FactoryBean,Implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves factories.
简介:
first,FactoryBean 是一个扩展点,主要是扩展创建复杂的对象实现。
second, 实现了FactoryBean接口的类自己就是一个factory,可以创建对象。接口一共三个方法,我们重点看一下其中的 getObject();
Object getObject(): returns an instance of the object this factory creates. The instance can possibly be shared, depending on whether this factory returns singletons or prototypes.
boolean isSingleton(): returns true if this FactoryBean returns singletons, false otherwise.
Class getObjectType(): returns the object type returned by the getObject() method or null if the type is not known in advance.
对照这个过程我们就阅读一下mybatis-spring MapperFactoryBean的源码,这里不再重复,请参考 http://blog.csdn.net/tanqidong1992/article/details/48026491
这里说明一下: sessionSqlTemplate 实现SqlSession, sessionSqlTemplates是线程安全的,所以在FactoryBean getObject的时候就注入了SqlSession,所以完成之后,mapper可以直接使用。
如果不看具体的代理对象生成过程,我们就可以理解了整个对象的创建过程,比如SqlSessionFactoryBean就使用了一个build方法。
FactoryBean 的好处就是简化复杂对象的创建,上面的创建过程绑定了sqlSession,通过代理生成了代理对象,这样使用起来就非常简单了。
Interface 生成代理对象
现在我们来看下为mapper接口生成代理对象的过程:
public class MapperRegistry {
private Configuration config;
// 为每个mapper类型存储一个对应的MapperProxyFactory
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
public MapperRegistry(Configuration config) {
this.config = config;
}
@SuppressWarnings("unchecked")
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
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
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
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;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}