mybatis 相关的源码详解笔记
初始化
现由此包进行初始化决议
1 2 3 4
| <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version>
|
进而配置
1 2 3 4 5 6 7
| Application启动类配置如下 @MapperScan("com.xxx.dao")
yaml中配置如下 mybatis: mapperLocations: classpath:mapper/**/*.xml typeAliasesPackage: com.ybxx.user.entity
|
初始化流程
@MapperScan
主要@Import(MapperScannerRegistrar.class)
从而引出MapperScannerRegistrar
去执行扫描basepackages任务
ClassPathMapperScanner
继承ClassPathBeanDefinitionScanner
作为主要执行扫描任务
扫描相关的类设置FactoryBean
为mapperFactoryBean
,后期直接从mapperFactoryBean#getObject
获取相关的数据操作对象
并为这个mapperFactoryBean
配置相关的SqlSessionFactory
等配置项
MapperFactoryBean#getObject
执行时,会引出getSqlSession().getMapper(this.mapperInterface);
从这引出MapperRegistry#getMapper
从而又引出MapperProxyFactory.MapperProxy
代理类在执行invoke操作的时候引出MapperMethod
(内部包裹SqlCommand
[MapperStatement]和MethodSignature
[ParamsResolver和ReturnSolver])
在MapperMethod
的SqlSession丢入SqlCommand#name
(MapperStatement#id)并用MethodSignature
的参数和返回解析整理
MapperInterface
ClassPathMapperScanner
MapperScannerConfigure&&MapperScannerRegistrar以上两个都用ClassPathMapperScanner的原理
它继承ClassPathBeanDefintionScanner,首先用了自己规则的registerFilters再父类的doScan获取到相关的beanDefinitions,
然后对beanDefinitions进行processBeanDefinitions处理
对beanDefinition的构造函数第一个参数设置当前的className
1
| definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
|
设置当前的beanDefinition实例化类为MapperFactoryBean
1
| definition.setBeanClass(this.mapperFactoryBean.getClass());
|
给当前beanDefinition设置sqlSessionFactory
1
| definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
|
MapperFactoryBean
因为实现InitializingBean,所以每次getObject之前先afterPropertiesSet—->checkDaoConfig
1 2
| Configuration configuration = getSqlSession().getConfiguration(); configuration.addMapper(this.mapperInterface);
|
当别的类比如Service层userService中带MapperInterface依赖,populate则会引入MapperFactoryBean的getObject
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Override public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); }
public SqlSession getSqlSession() { return this.sqlSession; }
public <T> T getMapper(Class<T> type) { return getConfiguration().getMapper(type, this); }
|
说白了就是从sqlSession引入configuration的mapperRegistry拿这个MapperInterface
MapperRegistry
由普通的getMapper引出MapperRegistry的MapperProxyFactory代理
从而MapperProxy代理引出MapperMethod
1 2 3 4 5
| MapperRegistry#getMapper ----> MapperProxyFactory.MapperProxy
MapperMethod ----> 内部有SqlCommand ----> 由之前设定的MapInterface转换相关的MappedStatement
MapperMethod ----> 内部还有MethodSignature, 参数转换(paramNameResolver),Return结果包装
|
接下来全部由MappedStatement#name
(就是mapperStatement的id
)去执行
于MapperMethod
方法内拿Sqlsession.select等方法传入MappedStatement#name
MapperProxyFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class MapperRegistry {
private final Configuration config; 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); } } ...... }
|
MapperProxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class MapperProxy<T> implements InvocationHandler, Serializable { @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); return mapperMethod.execute(sqlSession, args); } }
|
MapperMethod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| public class MapperMethod {
private final SqlCommand command; private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) { this.command = new SqlCommand(config, mapperInterface, method); this.method = new MethodSignature(config, mapperInterface, method); }
public Object execute(SqlSession sqlSession, Object[] args) { Object result; switch (command.getType()) { case INSERT: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); break; } case UPDATE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); break; } case DELETE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); break; } case SELECT: if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { result = executeForMap(sqlSession, args); } else if (method.returnsCursor()) { result = executeForCursor(sqlSession, args); } else { Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); } break; case FLUSH: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + command.getName()); } if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; } ...... }
|
SqlCommand
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) { final String methodName = method.getName(); final Class<?> declaringClass = method.getDeclaringClass(); MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration); if (ms == null) { if (method.getAnnotation(Flush.class) != null) { name = null; type = SqlCommandType.FLUSH; } else { throw new BindingException("Invalid bound statement (not found): " + mapperInterface.getName() + "." + methodName); } } else { name = ms.getId(); type = ms.getSqlCommandType(); if (type == SqlCommandType.UNKNOWN) { throw new BindingException("Unknown execution method for: " + name); } } }
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName, Class<?> declaringClass, Configuration configuration) { String statementId = mapperInterface.getName() + "." + methodName; if (configuration.hasStatement(statementId)) { return configuration.getMappedStatement(statementId); } else if (mapperInterface.equals(declaringClass)) { return null; } for (Class<?> superInterface : mapperInterface.getInterfaces()) { if (declaringClass.isAssignableFrom(superInterface)) { MappedStatement ms = resolveMappedStatement(superInterface, methodName,declaringClass, configuration); if (ms != null) { return ms; } } } return null; }
|
执行流程
DefaultSqlSessionFactory
工厂模式产DefaultSqlSession
,并通过configuration
生成executor
以及配置信息传递给DefaultSqlSession
DefaultSqlSession#insert|update|delete|selectList|selectOne|selectMap|selectCursor
由SqlSession引出以下实现类的各类操作
DefaultSqlSession
从configuration#getMappedStatement
根据ID获取具体的MappedStatement
交给executor
执行executor#update|query
executor
以CachingExecutor
为基础,装饰器模式套(SimpleExecutor
,ReuseExecutor
,BatchExecutor
其中一种)delegate执行executor#update|query
xxxExecutor#doQuery
根据MappedStatement
拿configuration
,再根据MappedStatement
执行configuration#newStatementHandler
生成StatementHandler
StatementHandler
划分为:PreparedStatementHandler
,CallableStatementHandler
,SimpleStatementHandler
xxxExecutor#prepareStatement
间接执行了上层基础类BaseStatementHandler#prepare
执行于各个子类instantiateStatement
根据mappedStatement
来执行connection.createStatement()
创建不同的Statement
最终在xxxExecutor
中让其执行StatementHandler#query|update|queryCursor
间接去执行statement.execute
基本组件
Builder
- XMLConfigBuilder
解析Config文件并添加到Configuration
- XMLMapperBuilder
解析Mapper文件并添加到Configuration
- XMLStatementBuilder
解析Mapper文件中的statement语句并添加到Configuration
Configuration总配置
DefaultSqlSession
默认的SqlSession
提供selectList,selectOne,insert,update,delete等方法
一般都有以下步骤
- 1:MappedStatement从configuration取出
- 2:executor去执行MappedStatement
到了executor有以下步骤
- 1:有缓存取缓存,没有通过MappedStatement来转换成合适的StatementHandler
- 2:StatementHandler通过prepareStatement转换合适的Statement
- 3:Statement.query执行并包装结果
Executor
CachingExecutor
BaseExecutor:SimpleExecutor,BatchExecutor
以上三种为执行器,sqlSession要执行具体的sql;必须在要在这三种执行器中执行Statement
如果开启二级缓存(默认开启),CachingExecutor装饰器模式套(SimpleExecutor,BatchExecutor其中一种)delegate,
所以去query首先先中二级缓存,但是CachingExecutor没有createCacheKey所以交给delegate去createCacheKey,
然后拿key去找缓存没有则继续delegate去找
delegate都是BaseExecutor继承,query->queryFromDatabase->doQuery
queryFromDatabase会去找当前selSession的一级缓存,内部是一个HashMap
StatementHandler
PreparedStatementHandler, CallableStatementHandler, CallableStatementHandler
SimpleExecutor或BatchExecutor要拿以上三种StatementHandler去执行
1 2 3 4 5 6 7 8 9 10 11
| public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
|
由MapperStatement转换而来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } }
|
由RoutionStatementHandler静态代理一个delegate:PreparedStatementHandler, CallableStatementHandler, CallableStatementHandler三者之一
DefaultResultSetHandler
StatementHandler返回的结果包装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Override public List<Object> handleResultSets(Statement stmt) throws SQLException { .... ResultSetWrapper rsw = getFirstResultSet(stmt); ..... while (rsw != null && resultMapCount > resultSetCount) { ..... handleResultSet(rsw, resultMap, multipleResults, null); .... } ..... }
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException { ResultSet rs = stmt.getResultSet(); while (rs == null) { ...... } return rs != null ? new ResultSetWrapper(rs, configuration) : null; }
|
typeAliases
一般在SqlSessionFactoryBean的变量设置了typeAliases,typeAliasesPackage这类变量,则直接configuration注册相关的alias
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| configuration.getTypeAliasRegistry().registerAlias(typeAlias);
public void registerAlias(Class<?> type) { String alias = type.getSimpleName(); Alias aliasAnnotation = type.getAnnotation(Alias.class); if (aliasAnnotation != null) { alias = aliasAnnotation.value(); } registerAlias(alias, type); }
public void registerAlias(String alias, Class<?> value) { if (alias == null) { throw new TypeException("The parameter alias cannot be null"); } String key = alias.toLowerCase(Locale.ENGLISH); if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) { throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'."); } TYPE_ALIASES.put(key, value); }
|
否则就是在configuration.xml文件里利用XmlConfigBuilder#parse–>parseConfiguration
typeAliasesElement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private void typeAliasesElement(XNode parent) { if (parent != null) { for (XNode child : parent.getChildren()) { if ("package".equals(child.getName())) { String typeAliasPackage = child.getStringAttribute("name"); configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage); } else { String alias = child.getStringAttribute("alias"); String type = child.getStringAttribute("type"); try { Class<?> clazz = Resources.classForName(type); if (alias == null) { typeAliasRegistry.registerAlias(clazz); } else { typeAliasRegistry.registerAlias(alias, clazz); } } catch (ClassNotFoundException e) { throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e); } } } } }
|
内部运用
TypeAliasRegistry在实例化会注册很多默认的别名映射类型
跟TypeHandlerRegistry一样,都会注册很多默认的Java类型映射数据库类型
用于XmlMapperBuilder中的cache,XmlStatementBuilder中的resultType,parameterType
typeHandler
跟typeAlias差不多,先从SqlSessionFactoryBean找,后从configuration.xml里面找
TypeHandlerRegistry初始化后会注册很多默认的Java类型映射数据库类型
1 2 3
| XmlConfigBuilder#parse---->parseConfiguration--->typeHandlerElement
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
|
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @MappedJdbcTypes(JdbcType.VARCHAR) public class ExampleTypeHandler extends BaseTypeHandler<String> {
@Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); }
@Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); }
@Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex); }
@Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } }
|
内部运用
主要运用resolveTypeHandler
1
| resolveTypeHandler(javaTypeClass, typeHandler);
|
- MapperBuilderAssistant#buildResultMapping
- MapperBuilderAssistant#buildParameterMapping
1 2 3 4 5
| public ResultMapping buildResultMapping(){ typeHandlerInstance = resolveTypeHandler(javaTypeClass, typeHandler) .... return new ResultMapping.Builder()..typeHandler(typeHandlerInstance).build(); }
|
使用
于DefaultResultSetHandler最后包装结果的时候使用
plugins
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。
默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
包装点
1 2 3 4 5 6 7 8 9 10 11 12 13
| XmlConfigBuilder#parseConfiguration----->pluginElement(root.evalNode("plugins"));
private void pluginElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { String interceptor = child.getStringAttribute("interceptor"); Properties properties = child.getChildrenAsProperties(); Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance(); interceptorInstance.setProperties(properties); configuration.addInterceptor(interceptorInstance); } } }
|
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Intercepts({@Signature( type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})}) public class ExamplePlugin implements Interceptor { public Object intercept(Invocation invocation) throws Throwable { return invocation.proceed(); } public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { } }
<!-- mybatis-config.xml --> <plugins> <plugin interceptor="org.mybatis.example.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins>
|
Plugin为InvocationHandler的jdk动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public static Object wrap(Object target, Interceptor interceptor) { Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor); Class<?> type = target.getClass(); Class<?>[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; }
@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); } }
|
执行点
分别对应
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| Configuration类
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) { ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql); parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); return parameterHandler; }
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) { ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler); return resultSetHandler; }
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }
public Executor newExecutor(Transaction transaction) { return newExecutor(transaction, defaultExecutorType); }
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { 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; }
|
interceptorChain.pluginAll(executor)主要执行点
二级缓存
基础
Mybatis默认对二级缓存是关闭的,一级缓存默认开启,如果需要开启只需在mapper上加入配置就好了
缓存策略
1.FIFOCache:先进先出算法回收策略
装饰类,内部维护了一个队列,来保证FIFO,一旦超出指定的大小,则从队列中获取Key并从被包装的Cache中移除该键值对。
1 2 3
| 内部保留Deque双端队列 每次put的时候检测队列是否size过1024限制 如果超过removeFirst,并把缓存也删除removeFirst的key
|
2.LoggingCache:输出缓存命中的日志信息,如果开启了DEBUG模式,则会输出命中率日志。
3.LruCache:最近最少使用算法
1 2 3
| 缓存回收策略,在内部保存一个LinkedHashMap默认size=1024并实现removeEldestEntry 在size过大的时候拿出来最不使用的delestKey key和value都存key,每次put检测delestKey有则将delegate缓存也删除相同key
|
4.ScheduledCache:定时1小时清空Cache,但是并没有开始一个定时任务,而是在使用Cache的时候,才去检查时间是否到了。
- 5.SerializedCache:序列化功能,将值序列化后存到缓存中。该功能用于缓存返回一份实例的Copy,用于保存线程安全。
6.SoftCache:基于软引用实现的缓存管理策略,软引用回收策略,软引用只有当内存不足时才会被垃圾收集器回收
1
| SoftReference包裹,get的时候发现为null了则删除delegate缓存里面的内容
|
7.SynchronizedCache:同步synchronized语法的缓存装饰器,用于防止多线程并发访问
- 8.PerpetualCache 永久缓存,一旦存入就一直保持,内部就是一个HashMap
- 9.WeakCache:基于弱引用实现的缓存管理策略
- 10.TransactionalCache 事务缓存,一次性存入多个缓存,移除多个缓存
- 11.BlockingCache 可阻塞的缓存,内部实现是ConcurrentHashMap
配置流程
SqlSessionFactoryBean 一个工厂bean,主要用于初始化SqlSession
由于是FactoryBean所以一切原由与getObject来初始化这个bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:mybatis-settings.xml"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean>
@Override public SqlSessionFactory getObject() throws Exception { if (this.sqlSessionFactory == null) { afterPropertiesSet(); } return this.sqlSessionFactory; }
@Override public void afterPropertiesSet() throws Exception { notNull(dataSource, "Property 'dataSource' is required"); notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required"); state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null), "Property 'configuration' and 'configLocation' can not specified with together"); this.sqlSessionFactory = buildSqlSessionFactory(); }
|
因为继承InitializingBean所以afterPropertiesSet会自动执行,但由于怕有些bean依赖于此提前getObject,所以设置了此方法
afterPropertiesSet引出buildSqlSessionFactory
主要buildSqlSessionFactory内部流程
- XMLConfigBuilder(针对config.xml)
XmlMapperBuilder(针对mapper.xml,parameterMap|resultMap|sql)
- XmlStatementBuilder(针对mapper.xml文件中select/update/delete/insert)负责构建MapperStatment
MapperBuilderAssistant辅助XmlMapperBuilder和XmlStatementBuilder来构建添加到configuration
- buildParameterMapping
- addParameterMap
- buildResultMapping
- addResultMap
- getStatementParameterMap
- getStatementResultMaps
包装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| XMLMapperBuilder#configurationElement
this.builderAssistant.setCurrentNamespace(namespace);
parameterMapElement(context.evalNodes("/mapper/parameterMap")); resultMapElements(context.evalNodes("/mapper/resultMap"));
这一部分的解析虽然利用了XmlMapperBuilder 其实间接性的利用了MapperBuilderAssistant#buildResultMapping---->addResultMap或者 MapperBuilderAssistant#buildParameterMapping--->addParameterMap 这里都是为了后期能够包装出MappedStatement而做的准备
|
国内查看评论需要代理~