demo示例
public class Test {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
inputStream.close();
}
@Test
public void testSelectAll() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper newsMapper = sqlSession.getMapper(UserMapper.class);
List<UserInfo> newsList = newsMapper.selectAll();
for (UserInfo news : newsList) {
System.out.println(news.getUserName());
}
sqlSession.close();
}
}
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"/>
<environments default="myEnv">
<environment id="env01">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver-class-name}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
db.properties
driver-class-name=com.mysql.jdbc.Driver
username=root
password=root
url=jdbc:mysql://192.168.127.147:3306
SqlSessionFactory构建
首先来看SqlSessionFactory
的构建过程,调用重载方法解析配置文件内容,将配置信息装载到Configuration对象中。
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 解析全局配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// parser.parse()得到Configuration配置对象
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
// 构建SqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
得到最终的SqlSessionFactory
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
}
SqlSession
接下来我们继续分析通过DefaultSqlSessionFactory
工厂方法获得SqlSession
的逻辑
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
// 从数据源获取SqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 通过环境变量获取数据源等
final Environment environment = configuration.getEnvironment();
// 1.创建事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 2.创建mybatis事务对象
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 3.新建执行器
final Executor executor = configuration.newExecutor(tx, execType);
// 4.将执行器封装到SqlSession中
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
这之中做了几件事情:
- 创建事务工厂
- 创建mybatis事务对象
- 新建执行器
- 将执行器封装到SqlSession中
对于获得事务工厂,事务工厂在解析配置文件时就已经确定,并保存在了Environment
对象中
创建事务对象-Transaction
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
// 环境变量属性
public final class Environment {
private final String id;
private final TransactionFactory transactionFactory;
private final DataSource dataSource;
}
针对于JdbcTransactionFactory获取事务,就是简单的工厂模式
public class JdbcTransactionFactory implements TransactionFactory {
@Override
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
}
我们继续看看JdbcTransaction
的封装信息
public class JdbcTransaction implements Transaction {
protected Connection connection;
protected DataSource dataSource;
protected TransactionIsolationLevel level;
protected boolean autoCommit;
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommit = desiredAutoCommit;
}
}
创建执行器-Executor
接下来继续看如何调用Configuration#newExecutor()
方法创建的执行器Executor
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// 默认使用SimpleExecutor
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
// 开启缓存的情况下,进行装饰代理
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 织入外部插件
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
插件也是相对简单的实现
拦截器增强
public class InterceptorChain {
// 所有插件
private final List<Interceptor> interceptors = new ArrayList<>();
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
// 插入
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
// 默认方法的包装增强代理
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
}
InvocationHandler实现-Plugin
而Plugin类是实现了InvocationHandler的动态代理基础类,
public class Plugin implements InvocationHandler {
// 被代理对象
private final Object target;
// 增强对象
private final Interceptor interceptor;
// 签名方法-需要拦截的方法
private final Map<Class<?>, Set<Method>> signatureMap;
// 构建InvocationHandler实现类对象
private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
this.target = target;
this.interceptor = interceptor;
this.signatureMap = signatureMap;
}
// 实现InvocationHandler的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
// 执行插件方法
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
// 针对对每个插件Interceptor,都会进行一次代理
public static Object wrap(Object target, Interceptor interceptor) {
// 获取需要拦截方法的Map
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
// Plugin实现了InvocationHandler,执行时会调用invoke方法
return Proxy.newProxyInstance(type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
// 插件必须带有@Intercepts注解
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
// issue #251
if (interceptsAnnotation == null) {
throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
}
Signature[] sigs = interceptsAnnotation.value();
Map<Class<?>, Set<Method>> signatureMap = new HashMap<>();
// 解析当前插件拦截哪些类实现的方法
for (Signature sig : sigs) {
Set<Method> methods = MapUtil.computeIfAbsent(signatureMap, sig.type(), k -> new HashSet<>());
try {
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException e) {
throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
}
}
return signatureMap;
}
private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
Set<Class<?>> interfaces = new HashSet<>();
while (type != null) {
// 该类是否需要被插件运用拦截
for (Class<?> c : type.getInterfaces()) {
if (signatureMap.containsKey(c)) {
interfaces.add(c);
}
}
type = type.getSuperclass();
}
return interfaces.toArray(new Class<?>[0]);
}
}
@Intercepts注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
Signature[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {
// 拦截何种类型
Class<?> type();
// 拦截的方法名称
String method();
// 方法参数签名
Class<?>[] args();
}
继续看DefaultSqlSession的创建,保存了执行器,配置信息以及事务是否自动提交。文章来源:https://www.toymoban.com/news/detail-435670.html
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
}
最终得到了一个构建好的DefaultSqlSession,其拥有了执行器。文章来源地址https://www.toymoban.com/news/detail-435670.html
到了这里,关于SqlSession的初始化过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!