整体执行流程
入口类为MybatisAutoConfiguration整体分为两步:
- 扫描
@Mapper注解生成注解对应的BeanDefinition。 - 创建
SqlSessionFactory工厂
整体执行流程如图:
主要的类
以下的类代码只关心核心逻辑,删去了if和catch等操作。
ClassPathMapperScanner
ClassPathMapperScanner 是扫描@Mapper注解的主要扫描类,scan()方法中会调用父类 ClassPathBeanDefinitionScanner#scan() 的方法在父类中注册扫描到的Mapper接口,然后在对 BeanDefinition 进行后置处理。
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
// 省略其他方法和属性
// Mapper接口的BeanClass类型
private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 使用父类注册BeanDefinition
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
// 打日志
} else {
//对BeanDefinition进行二次处理
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
.........
// 设置BeanDefinition的BeanClass
definition.setBeanClass(this.mapperFactoryBeanClass);
........
}
}
在生成该类并且进行扫描时,并没有开始创建SqlSessionFactory
MapperFactoryBean
从上面的扫描类中可以看出BeanDefinition的BeanClass=MapperFactoryBean。
extends SqlSessionDaoSupport,为子类提供了SqlSessionTemplate的实例,子类可以通过getSqlSession()获取SqlSessionTemplate。implements FactoryBean<T>,getObject()可以提供@Mapper接口对应的MapperProxy的实例。
结构如下:
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
public MapperFactoryBean() {
// intentionally empty
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Override
public T getObject() throws Exception {
// 这里调用了父类的方法得到了SqlSession
return getSqlSession().getMapper(this.mapperInterface);
}
}
/*******************************************************************/
// 上述getMapper逻辑如下
@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}
// 最后从MapperRegistry中得到了代理对象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry、MapperProxyFactory、MapperProxy
一句话:MapperRegistry缓存MapperProxyFactory,MapperProxyFactory创建MapperProxy。
MapperRegistry 中存放着Mybatis解析mapper.xml时,namesapce对应的接口和 MapperProxyFactory 的缓存。
public class MapperRegistry {
private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
public MapperRegistry(Configuration config) {
this.config = config;
}
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
boolean loadCompleted = false;
knownMappers.put(type, new MapperProxyFactory<>(type));
// 这里是对接口方法上的@Select、@Update注解做解析
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
}
}
// 针对Mapper创建代理类时最后会调用该方法
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
//报错
}
// 只有获取Mapper的使用才会创建MapperProxy
return mapperProxyFactory.newInstance(sqlSession);
}
}
MapperProxyFactory 是创建接口代理的工厂类,结构如下
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
// 缓存接口中已经生成的代理方法
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
@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<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
MapperProxy 对象作为最终的代理对象实现了动态代理接口
public class MapperProxy<T> implements InvocationHandler, Serializable {
// 全部从MapperProxyFactory传入
// 传入SqlSessionTemplate,最终执行SQL的对象
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
}
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
MapperMethodInvoker invoker = methodCache.get(method);
if (invoker != null) {
return invoker;
}
return methodCache.computeIfAbsent(method, m -> {
if (m.isDefault()) {
// 处理接口中的default方法
} else {
// 再这里创建mapper.xml中指定的方法
return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
});
}