直接上图:
纯 Mybatis 操作时:
- 解析mybatis-config.xml赋值mybatis的Configuration,扫描注册的 *.xml,生成
protected final Map
mappedStatements; key
为 全限定名加接口方法名,每个value为解析select
、delete
等标签
对应的MappedStatement
对象- 并扫描路径下对应mapper接口在
mapperRegistry
,其中包含属性Map
;, MapperProxyFactory>> knownMappers = new HashMap() key
为对应接口class文件,value为MapperProxyFactory
,构造函数对象赋值mapperInterface
sqlSession.getMapper(TestMapper.class)
,传入对应mapper接口的 class,在 mapperRegistry获取对应的MapperProxyFactory
其中有对应的类加载器,类接口,Invocation程序处理调用程序,因为MapperProxy
,每一个implements InvocationHandler MapperProxy
实际为一个InvocationHandler,重写invoke()
方法,执行具体方法逻辑- 然后生成对应的
代理类
,由代理类执行真是业务方法,在 MapperMethod,invoke()中,根据参数获取对应MappedStatement
对应,传入Executor
执行器,执行 具体jdbc,并封装返回结果集
- MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(this.command.getName());
MapperProxyFactory
{ 映射器代理工厂
在Spring boot 中,注入
UserMapper userMapper;
,其实就是注入具体的代理类
,由代理执行具体方法。
- 不可能裸注入接口,而没有具体实现撒
注意:
sqlSession.getMapper(TestMapper.class)
,是获取mapperRegistry
中对应的MapperProxyFactory
,由
mapperProxyFactory.newInstance(sqlSession)
//构建对应,Invocation 调用处理类 MapperProxy
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);
}
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
InputStream inputStream = null;
try {
//读取全局配置xml
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
} catch (IOException e) {
e.printStackTrace();
}
//解析xml,从跟节点 configuration 开始逐个取值,并赋值到 Configuration 对象,并且返回 DefaultSqlSessionFactory 对象。( 其中也包含 注册的 mapper.xml的解析 )
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//this.build(parser.parse());
// this.mapperElement(root.evalNode("mappers")); --> mapper.xml 解析,封装 MappedStatement对象
// 存储在Configuration对象的mappedStatements属性中,mappedStatements 是一个HashMap,存储时key = 全限定类名 + 方法名,value = 对应的MappedStatement对象。
//return new DefaultSqlSessionFactory(config);
//this.parseConfiguration(this.parser.evalNode("/configuration"));
}
// 开启事务管理,创建执行器,返回 SqlSession
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
/*
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
*/
}
@org.junit.Test
public void example(){
//sqlsession是线程不安全的,一次会话结束关闭资源
SqlSession sqlSession = MybatisUtil.getSqlSession();
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
List<Test> all = mapper.all();
System.out.println(all);
sqlSession.close();
}
// 通过动态代理实现, mapperMethod.execute(sqlSession, args); 实现逻辑处理
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//判断调用是是不是Object中定义的方法,toString,hashCode这类非。是的话直接放行。
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);
return mapperMethod.execute(sqlSession, args);
}
核心原理流程:
- 读取全局配置xml,获取配置文件输入流,由 SqlSessionFactoryBuilder解析创建 SqlSessionFactory,其中包含 赋值 Configuration,以及解析注册的mapper.xml 并封装为MappedStatement(HashMap),为Configuration的一个属性值。
- sqlSessionFactory.openSession() 开启获取一个sqlsession,创建事务管理器,Executor 执行器,返回一个sqlsesion对象
- 具体执行 TestMapper mapper = sqlSession.getMapper(TestMapper.class),通过传入 具体业务mapper对象字节码,获取代理 MapperProxyFactory 代理工厂,以及当前 sqlseesion - > mapperProxyFactory.newInstance(sqlSession); 获取当前对象代理对象,并调用方法,执行时(动态代理)实现方法增强,mapperMethod.execute(sqlSession, args),最后由executor具体执行业务处理
Spring boot + Mybatis 时:
- 整合步骤:
- 导入
mybatis-spring-boot-starter
application.yml
配置spring.datasource
数据源,以及mybatis.mapper-locations: classpath:xml/*.xml
- Springboot 启动类,添加
@MapperScan("com.mapper")
,mapper扫描 / 或@Mapper
标注mapper接口
–只需要这三步,就可以开用如:
userMapper.searchAll();
流程原理解析:
springboot自动装配,加载
/META-INF
下spring.factories
,properties
-> 加载org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
,->MybatisAutoConfiguration
导入spring容器.
1.注解类标住
@MapperScan("com.mapper")
扫描mapper时:
会通过配置的基础路径扫描全部的mapper接口,注入spring容器。
2.mapper接口标识
@Mapper
时
MybatisAutoConfiguration
自动配置类中,AutoConfiguredMapperScannerRegistrar
,会扫描标识了@Mapper
的接口,注入容器。
SqlSessionFactory实例化;
具体执行: 该有的都有了,在
userMapper.searchAll();
时,跟纯mybaits
时差不多了。