示范校建设专题网站四平卫生学校,动叫建个网站刷排名,wordpress机械模板下载地址,wordpress搜索插件提前写在前面 前段时间做过一个项目#xff0c;期间用到了动态数据源dynamic-datasource#xff0c;经历了dbcp2的数据库连接池没有生效到排查定位、MyBatis多种数据库产品兼容、手写MyBatis拦截器等事情。 花费了好久#xff0c;一直在打磨这篇文章#xff08;不知道花费这么长…写在前面 前段时间做过一个项目期间用到了动态数据源dynamic-datasource经历了dbcp2的数据库连接池没有生效到排查定位、MyBatis多种数据库产品兼容、手写MyBatis拦截器等事情。 花费了好久一直在打磨这篇文章不知道花费这么长时间写文章有没有意义但互联网总得留下点儿什么吧~。最终千呼万唤始出来。本文就从源码的角度来系统地看看原理是什么能学到些什么。如有说的不正确的地方欢迎指正。 目录 写在前面一、环境说明二、为什么如何做三、动态数据源部分一动态数据源加载、连接池创建 四、MyBatis部分一 MyBatis核心组件加载二MapperProxy初始化三连接池的使用、数据库厂商加载、拦截器生效 五、收获六、附录plantuml脚本activity_baomidou_dynamicdatasource.pumlactivity_mybatis_sqlsessionfactorybean.pumlactivity_mybatis_mapperproxy.pumlactivity_mybatis_conn_interceptor.pumlclass_baomidou.pumlclass_mybatis.puml 写在后面系列文章 一、环境说明
名称说明mybatis版本mybatis-3.4.6.jarmybatis-spring版本mybatis-spring-1.3.1.jarmybatis-spring-boot版本mybatis-spring-boot-autoconfigure-1.3.0.jardynamic-datasource-spring-boot-starter版本dynamic-datasource-spring-boot-starter-3.5.2.jarcommons-dbcp2版本commons-dbcp2-2.8.0.jarIDEA编辑器2019PlantUML插件IDEA / VsCode插件 二、为什么如何做
说正题前我们先思考一下为什么要看源码
我想可能有几种场景
1、出问题了不得不看。
比如在项目中引入了什么包、配置或者做了什么改动导致项目无法启动或者报错了
2、求知欲。有疑问带着问题看。
比如本文将要讨论的dbcp2连接池是什么时机创建的如何创建的又是怎么使用的MyBatis拦截器插件是如何生效的等等
3、面试。 不过比起八股文自己研究一下体会会更深。那看源码我们能收获什么 个人认为看源码可以去切实地体会优秀的代码设计了解高手是怎么做的包括设计模式的运用、扩展点、设计原则等等。思考如果自己以后遇到类似问题该如何运用。不熟悉设计模式这部分内容的朋友可以去参考这篇文章【GitHub】- design-pattern设计模式
另外看源码笔者还有一个提示不要一下子要求全搞懂否则你会越陷越深… 看到最后不知所云。根据当下的水平逐步丰富自己的体系建议带着问题带着疑问点到为止问题搞懂不要无限蔓延
那究竟该如何看这里我谈一谈自己的见解正文内容也是这么做的。
稍微扩展一下延展到如何学习一个新的框架或者新的知识点
1、通读官方文档、GitHub的README
知道这个框架是做什么的主要用于解决什么问题了解框架的架构图
2、结合官方Demo熟悉基本操作API
3、自己动手
写Demo本地调试。梳理流程主要包括2部分内容类图和活动图
画类图能让你快速全面地了解到这个类是干什么用的有什么样的体系继承、实现、依赖以及关联关系
画活动图能让你知道这些类的调用关系、这些类是如何相互作用使用的。不熟悉类图和活动图的这部分朋友可以去参考这篇文章【UML】- 类图
看源码首先看什么能最快地找到突破口
我认为
首先看它的pom.xml看依赖关系pom中有什么jar包可能就会具备哪些功能
其次看源码的包命名优秀的代码内聚做的比较好
然后从resource开始着手可能有一些配置需要提前了解好了接下里我们回归正题。 以下从2个部分开始说主要包括动态数据源和MyBatis。 三、动态数据源部分 一动态数据源加载、连接池创建
首先找到 dynamic-datasource-spring-boot-starter-3.5.2.jar 我们在resource下找到了META-INF/spring.factories咦这是什么这不就是自动装配么。好了找到切入口了。
org.springframework.boot.autoconfigure.EnableAutoConfiguration\
com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration看看 DynamicDataSourceAutoConfiguration 干了什么事情
# DynamicDataSourceAutoConfiguration
1.将 yml 中的配置信息数据源url/driver、连接池等等配置信息构建成Bean加入到Spring容器
2.通过 Import 导入creator的自动配置类 DynamicDataSourceCreatorAutoConfiguration进行creator初始化2.1 创建一个 DefaultDataSourceCreator(ListDataSourceCreator dataSourceCreators)构造注入dataSourceCreators与DataSourceCreator绑定关系也就是dbcp2的creator2.2 判断classpath中有dbcp2的包创建 Dbcp2DataSourceCreator
3.创建 YmlDynamicDataSourceProvider()3.1 通过构造方法和 dataSourcePropertiesMap 进行了绑定3.1 通过继承属性注入 DefaultDataSourceCreator和creator进行了绑定
4.创建 DynamicRoutingDataSource 路由4.1 Autowired 属性注入 provider也就是 YmlDynamicDataSourceProvider4.2 实现了InitializingBean初始化Bean时会调用afterPropertiesSet我们先梳理一下这里边的几个绑定关系 DynamicRoutingDataSource 路由包含一个 YmlDynamicDataSourceProvider YmlDynamicDataSourceProvider 中有 dataSourcePropertiesMap 和 DefaultDataSourceCreator DefaultDataSourceCreator 中有 List包含了dbcp的creator。
该初始化的进行初始话该绑定的关系的绑定关系。 接下来我们重点看 DynamicRoutingDataSource#afterPropertiesSet() 动态数据源加载的过程也就是连接池的创建过程。
# DynamicRoutingDataSource#afterPropertiesSet()
1.调用 provider#loadDataSources()# YmlDynamicDataSourceProvider
2.调用 defaultDataSourceCreator#createDataSource# DefaultDataSourceCreator
3.调用 dbcp2#doCreateDataSource(dataSourceProperty)# BasicDataSource
4.调用 dbcp2的连接池去创建数据源 dataSource#start()4.1 for循环配置文件中的 initialSizeconnectionPool.addObject() 添加到LinkedBlockingDeque中至此连接池就创建完毕了。
以下是活动图和类图 温馨提示鼠标右键-》在新标签页中打开图片可查看高清图。PlantUML脚本在附录部分
有了类图就很明显了这里面有3个体系
DataSourcespring实现了AbstractDataSource
DataSourceCreator
DynamicDataSourceProvider相应地对应了有3个抽象类
1.AbstractRoutingDataSource
这个类在连接池创建的时候没用到这里也说一下在获取时为重载DataSource#getConnection 添加一个determineDataSource()获取连接池的操作
具体实现在DynamicRoutingDataSource中2.AbstractDataSourceCreator
抽象连接池创建器这里边抽象出一个 doCreateDataSource(DataSourceProperty dataSourceProperty)由具体的实现类dbcp2、druid、Hikari实现
另外在doCreateDataSource前后做了一些通用逻辑
// 源码
dataSourceInitEvent.beforeCreate(dataSourceProperty)
DataSource dataSource doCreateDataSource(dataSourceProperty);
dataSourceInitEvent.afterCreate(dataSource)3.AbstractDataSourceProvider
多数据源加载接口默认的实现为从yml信息中加载所有数据源。
抽象出接口就可以扩展一些其他加载数据源的方式四、MyBatis部分
一 MyBatis核心组件加载 首先找到 mybatis-spring-boot-autoconfigure-1.3.0.jar 在resource下找到了META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration看一下MybatisAutoConfiguration做了什么事情。
# MybatisAutoConfiguration
1.AutoConfigureAfter优先注入datasource数据源
2.通过datasource数据源构造方式 SqlSessionFactoryBean绑定了数据源2.1 设置datasource、configuration2.2 由于实现了InitializingBean初始化Bean时会调用afterPropertiesSet2.2.1 处理configuration、添加Interceptor、databaseId、创建事务工厂、解析xml对象最后构建一个DefaultSqlSessionFactory
3.通过sqlsesssionfactory创建sqlSessionTemplate3.1 构造方法中隐藏了一个sqlSessionProxy代理它代理了SqlSession接口通过SqlSessionInterceptor的invoke实现逻辑说明这里SqlSessionTemplate定义了一套操作Mybatis的模板实际上方法的执行调用的都是SqlSession的实现类方法
因为框架想在操作完方法之后处理一些事务的提交、session的关闭等操作实现方式是使用代理Proxy代理SqlSession
以下是活动图 温馨提示鼠标右键-》在新标签页中打开图片可查看高清图。PlantUML脚本在附录部分
二MapperProxy初始化 我们知道接口是无法执行方法的这里MyBatis把所有的mapperInterface代理成了MapperProxy。以下是MapperProxy的创建过程活动图 温馨提示鼠标右键-》在新标签页中打开图片可查看高清图。PlantUML脚本在附录部分
三连接池的使用、数据库厂商加载、拦截器生效 以下是MyBatis操作整体流程活动图 温馨提示鼠标右键-》在新标签页中打开图片可查看高清图。PlantUML脚本在附录部分
我们以一个示例 baseMapper.queryByList(map) 作为入口来说明 执行baseMapper#queryByList()实际上调用的是 mapperproxy#invoke前面提到了mapperproxy代理了baseMapper
mapperproxy调用了mapperMethod#execute(sqlSession, args)
# MapperMethod
1.根据 SqlCommandType 执行SQL也就是判断 CRUD然后通过SqlSession做相应操作这里的重点来了SqlSession现在是什么SqlSession是SqlSessionTemplate也就是会调用SqlSessionTemplate#selectList
在源码里你会看到接着调用的是 sqlSessionProxy#selectList,sqlSessionProxy我们前面提到过是代理的SqlSessionInvokeHandler是SqlSessionInterceptor
那么此时就会调用SqlSessionInterceptor#invoke# SqlSessionInterceptor
2.这是一个模板的方法进行了3个操作2.1 获取真正要处理的 getSqlSession2.2 执行方法2.3 判断事务操作提交事务2.4 关闭session接下来详细说一下[2.1] getSqlSession()干了什么事情它通过前面创建的 DefaultSqlSessionFactory 创建一系列的组件。
# DefaultSqlSessionFactory
2.1.1根据datasource创建tx事务transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit)
2.1.2.创建Executor执行器configuration.newExecutor(tx, execType)2.1.2.1 这个executor执行器会经过拦截器链分页、自定义的属性填充的包装这里又是一个Plugin的代理会代理executor里面的方法在真正方法执行前先执行这些拦截器的操作2.1.2.2 最终返回一个DefaultSqlSession对象当执行[2.2] 的方法时通过反射的方式调用就是DefaultSqlSession#selectList
#DefaultSqlSession
2.2.1 这里边会去获取到databaseId的sql
2.2.2 先去执行拦截器链中的拦截器分页、属性填充
2.2.3 要获取Connection2.2.3.1 从事务中获取datasource此时的datasource在DynamicRoutingDataSource的datasourceMap中2.2.3.2 拿到datasource后dbcp2的datasource会调用getConnection从 LinkedBlockingDeque#pollXxx()以下是MyBatis的类图 看看类图你至少知道什么是datasource、什么是connection、什么是sqlsession对他们的关系有了进一步的理解了吧。 温馨提示鼠标右键-》在新标签页中打开图片可查看高清图。PlantUML脚本在附录部分 五、收获
面向接口编程抽象类实现通用逻辑也可以通过模板的方式实现通用逻辑一些自动配置我们可以通过starter自动装配实现关系的构建可以通过Bean初始化去实现InitializingBean进而通过属性或者构造方法的方式去注入一些你需要的Bean可以通过注入Event的这种方式去做一个before和after的事情也可以通过代理的方式实现优秀名的命名、编码风格 … 六、附录plantuml脚本
activity_baomidou_dynamicdatasource.puml
startuml
skinparam style strictuml
skinparam sequenceMessageAlign direction
skinparam roundcorner 20
skinparam sequenceParticipant underline
autoactivate ontitle 【动态数据源加载及连接池创建】活动图baomidou
participant ddsa_config (C,#ADD1B2) DynamicDataSourceAutoConfiguration
note over of ddsa_config #aqua自动装配核心Bean创建的入口
end noteparticipant dds_properties (C,#ADD1B2) DynamicDataSourceProperties
participant ds_property (C,#ADD1B2) DataSourceProperty
note over dds_properties, ds_propertyyml属性对应的Bean内外层
end noteparticipant dds_creator_a_config (C,#ADD1B2) DynamicDataSourceCreatorAutoConfiguration
note over of dds_creator_a_configcreator自动配置
end noteparticipant ads_creator (A,#A8DEDF) AbstractDataSourceCreator
participant dds_creator (C,#ADD1B2) DefaultDataSourceCreator
participant dbcp2ds_creator (C,#ADD1B2) Dbcp2DataSourceCreator
note over dds_creator_a_config, dbcp2ds_creatorcreator体系
end noteparticipant ads_provider (A,#A8DEDF) AbstractDataSourceProvider
participant ydds_provider (C,#ADD1B2) ymlDynamicDataSourceProvider
note over of ydds_provider #aqua组件的关系绑定
end note
note over ads_provider, ydds_providerprovider体系
end noteparticipant drds (C,#ADD1B2) DynamicRoutingDataSource
note over of drds #aqua动态数据源加载入口
end notedbcp2
participant basic_ds (C,#ADD1B2) BasicDataSource
note over of basic_dsdbcp2连接池
end note- ddsa_config: dynamic-datasource-spring-boot-starter-3.5.2.jar 自动装配 META-INF/spring.factories\n EnableAutoConfigurationc.b.d.d.s.b.autoconfigure.DynamicDataSourceAutoConfiguration
yml配置文件的加载以及初始化group yml配置构建成Bean加入spring容器ddsa_config - dds_properties: EnableConfigurationPropertiesdds_properties - ds_property: private MapString, DataSourceProperty datasource \n new LinkedHashMap()ds_property -- ddsa_config: yml填充后加入spring容器
endgroup Import导入creatorddsa_config - dds_creator_a_config: Importgroup creator初始化group 创建默认的creatordds_creator_a_config - dds_creator_a_config: dataSourceCreator(ListDataSourceCreator dataSourceCreators)\ncolor red 与DataSourceCreatordbcpCreator绑定关系dds_creator_a_config - dds_creator: new DefaultDataSourceCreator()dds_creator -- dds_creator_a_config: color red提供了createDataSource(dataSourceProperty)方法endgroup 创建dbcp2的creatordds_creator_a_config - dds_creator_a_config: dbcp2DataSourceCreator()dds_creator_a_config - dbcp2ds_creator: new Dbcp2DataSourceCreator()dbcp2ds_creator -- dds_creator_a_config: color red提供了 doCreateDataSource(DataSourceProperty dataSourceProperty) 方法endgroup 创建其他的creator(ConditionalOnClass(BeeDataSource.class))dds_creator_a_config - dds_creator_a_config: ...endenddds_creator_a_config -- ddsa_config: DynamicDataSourceCreatorAutoConfiguration 被创建
endgroup 构造方法 注入 DynamicDataSourceProperties 和 ListDynamicDataSourcePropertiesCustomizerddsa_config - ddsa_config: DynamicDataSourceAutoConfiguration(properties, dataSourcePropertiesCustomizers)\n color red目的是拿到yml中的配置为其他Bean传参
endgroup 创建YmlDynamicDataSourceProviderddsa_config - ydds_provider : ymlDynamicDataSourceProvider(),\n new对象把datasource这个Map(每一个数据源)作为构造参数传入, color red相当于和dataSourcePropertiesMap进行了绑定ydds_provider - ads_provider: Autowigreen DefaultDataSourceCreator defaultDataSourceCreator\n属性注入color red相当于和creator进行了绑定ads_provider -- ydds_providerydds_provider -- ddsa_config: color red提供loadDataSources()方法
endgroup 创建 DynamicRoutingDataSource 路由ddsa_config - drds: dataSource()\n new对象依据DynamicDataSourceProperties的属性设置自身,比如primary属性group Autowired属性注入providersdrds - drds: Autowired ListDynamicDataSourceProvider providers color red此处的provider就是创建YmlDynamicDataSourceProviderenddrds -- ddsa_config: color red由于实现了InitializingBean提供 afterPropertiesSet() 方法连接池创建group #EEE 实现了InitializingBean重写afterPropertiesSetdrds - drds #aqua: Override afterPropertiesSetdrds - ydds_provider: provider.loadDataSources()ydds_provider - ads_provider: createDataSourceMap(dataSourcePropertiesMap)ads_provider - dds_creator: createDataSource(DataSourceProperty dataSourceProperty)dds_creator - ads_creator: createDataSource(DataSourceProperty dataSourceProperty)ads_creator - ads_creator: color red __abstract doCreateDataSource(dataSourceProperty)__\n color red由连接池实现,以dbcp2为例ads_creator - dbcp2ds_creator: doCreateDataSource(DataSourceProperty dataSourceProperty)dbcp2ds_creator - basic_ds: start()group #EEE 真正创建连接池basic_ds - basic_ds: createDataSource()basic_ds - basic_ds: color redfor循环连接池initialSize\n color redconnectionPool.addObject()\r color red添加到LinkedBlockingDeque中endbasic_ds -- drdsend
endendumlactivity_mybatis_sqlsessionfactorybean.puml
startuml
skinparam style strictuml
skinparam sequenceMessageAlign direction
skinparam roundcorner 20
skinparam sequenceParticipant underline
autoactivate ontitle 【MyBatis核心组件加载】活动图
ibatis
participant mba_config (C,#ADD1B2) MybatisAutoConfiguration
note over of mba_config #aqua自动装配核心Bean创建的入口
end notespring
participant dsa_config (C,#ADD1B2) DataSourceAutoConfiguration participant ssf_bean (C,#ADD1B2) SqlSessionFactoryBean
note over of ssf_bean #aqua构建SqlSessionFactory的入口
end notemybatis
participant ss_template (C,#ADD1B2) SqlSessionTemplate participant ssf_builder (C,#ADD1B2) SqlSessionFactoryBuilder
participant dss_factory (C,#ADD1B2) DefaultSqlSessionFactory
note over ssf_bean, dss_factorySqlSession相关
end note- mba_config: mybatis-spring-boot-autoconfigure-1.3.0.jar 自动装配 META-INF/spring.factories\n EnableAutoConfigurationo.m.s.b.autoconfigure.MybatisAutoConfiguration
加载yml配置文件及初始化group 优先注入 DataSourceAutoConfigurationmba_config - dsa_config: AutoConfigureAfterdsa_config -- mba_config
endgroup 构造方法方式 给私有属性赋值mba_config - mba_config: MybatisProperties\n ObjectProviderInterceptor[]\n ResourceLoader\n ObjectProviderDatabaseIdProvider\n ObjectProviderListConfigurationCustomizer)
endgroup #EEE 创建 SqlSessionFactory(DataSource dataSource)mba_config - mba_config: sqlSessionFactory(DataSource dataSource), new对象创建 SqlSessionFactoryBean\n//设置setDataSource、setConfiguration、\n//setPlugins、setDatabaseIdProvider、setMapperLocations(解析classpath:/mapper/*Mapper.xml)mba_config - ssf_bean: getObject()group #EEE 创建SqlSessionFactoryssf_bean - ssf_bean #aqua: afterPropertiesSet()ssf_bean - ssf_bean: buildSqlSessionFactory()\ncolor red//处理configuration\ncolor red//addInterceptor(plugin)\ncolor red//setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource))\ncolor red//创建SpringManagedTransactionFactory\ncolor red//xmlMapperBuilder.parse();\nbuilderAssistant.addMappedStatement(databaseId)\ncreateSqlSource():SqlSourcessf_bean - ssf_builder: this.sqlSessionFactoryBuilder.build(configuration)ssf_builder - ssf_builder: build(config)ssf_builder - dss_factory: color rednew DefaultSqlSessionFactory(config)dss_factory -- ssf_beanendssf_bean -- mba_config
endgroup 创建 SqlSessionTemplatemba_config - mba_config: sqlSessionTemplate(SqlSessionFactory sqlSessionFactory)mba_config - ss_template: new SqlSessionTemplate()group #EEE 构造方法ss_template - ss_template: SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, \nExecutorType executorType,\nPersistenceExceptionTranslator exceptionTranslator)\ncolor red//隐藏了一个代理\nthis.sqlSessionProxy (SqlSession) newProxyInstance(\nSqlSessionFactory.class.getClassLoader(),\nnew Class[] { SqlSession.class },\nnew SqlSessionInterceptor());endss_template -- mba_config
endendumlactivity_mybatis_mapperproxy.puml
startuml
skinparam style strictuml
skinparam sequenceMessageAlign direction
skinparam roundcorner 20
skinparam sequenceParticipant underline
autoactivate ontitle 【MyBatis MapperProxy 初始化】活动图
spring
participant ab_factory (C,#ADD1B2) AbstractBeanFactory participant mf_bean (C,#ADD1B2) MapperFactoryBean
participant ss_template (C,#ADD1B2) SqlSessionTemplate participant config (C,#ADD1B2) Configuration
participant mregistry (C,#ADD1B2) MapperRegistry participant mp_factory (C,#ADD1B2) MapperProxyFactory
participant mproxy (C,#ADD1B2) MapperProxy - ab_factory: 项目启动service 注入 daoMapperProxy 的初始化
ab_factory - ab_factory: getBean(String name, ClassT requiredType)\n入参示例(configPropertiesDao, com.zhht.dao.ConfigPropertiesDao)
ab_factory - ab_factory: getObjectFromFactoryBean(factory, beanName, !synthetic)ab_factory - ab_factory: getObject()ab_factory - mf_bean
mf_bean - mf_bean: getObject()\ncolor redgetSqlSession().getMapper(this.mapperInterface)
mf_bean - ss_template: getMapper(this.mapperInterface)ss_template - ss_template: getMapper(ClassT type)\n//getConfiguration().getMapper(type, color redthis/color)
ss_template - config: getMapper(ClassT type, SqlSession sqlSession)config - mregistry: getMapper(ClassT type, SqlSession sqlSession)
mregistry - mp_factory:(MapperProxyFactoryT) knownMappers.get(type)mp_factory - mproxy: newInstance(sqlSession):\ncolor rednew MapperProxyT(sqlSession, mapperInterface, methodCache)
mproxy -- ab_factoryendumlactivity_mybatis_conn_interceptor.puml
startuml
skinparam style strictuml
skinparam sequenceMessageAlign direction
skinparam roundcorner 20
skinparam sequenceParticipant underline
autoactivate ontitle 【连接池使用及数据库厂商加载】活动图
participant mproxy (C,#ADD1B2) MapperProxy
participant mmethod (C,#ADD1B2) MapperMethod participant ss_template (C,#ADD1B2) SqlSessionTemplate
note over of ss_template #aqua模板方法控制流程
end noteparticipant dss_factory (C,#ADD1B2) DefaultSqlSessionFactory
note over of dss_factory #aqua核心组件的创建
end noteparticipant sm_transaction (C,#ADD1B2) SpringManagedTransaction
participant config (C,#ADD1B2) Configuration participant mstatement (C,#ADD1B2) MappedStatement participant ds_session (C,#ADD1B2) DefaultSqlSession
participant bexecutor (C,#ADD1B2) BaseExecutor
participant shandler (C,#ADD1B2) StatementHandler participant interceptor_chain (C,#ADD1B2) InterceptorChain
participant interceptor (C,#ADD1B2) Interceptor
participant plugin (C,#ADD1B2) Plugin
note over interceptor_chain, plugin拦截器
end noteparticipant dr_datasource (C,#ADD1B2) DynamicRoutingDataSource
participant dbc2_datasource (C,#ADD1B2) BasicDataSource
note over dr_datasource, dbc2_datasource数据源
end note- mproxy: baseMapper.queryByList(map)
入口mproxy - mproxy: Object invoke(Object proxy, \nMethod method, Object[] args)
mproxy - mmethod: mapperMethod.execute()group #EEE 根据 SqlCommandType 执行SQLmmethod - mmethod: Object execute(SqlSession sqlSession, Object[] args)\n color red// 难点sqlSession.selectList()\n color red此处的sqlSession是SqlSessionTemplate\n color red// 调用 this.sqlSessionProxy.E selectList(statement, parameter)\n color red 此处的 sqlSessionProxy的 invokeHandler 是SqlSessionInterceptormmethod - ss_template: invoke(因为是代理对象所以要执行 SqlSessionInterceptor.invoke)
endss_template - ss_template: invoke(Object proxy, Method method, Object[] args)
ss_template - dss_factory: getSqlSession()对象的创建
group 创建 SqlSessiondss_factory - dss_factory: openSession(executorType)group #EEE 创建组件 tx、Executor、DefaultSqlSessiondss_factory - dss_factory: openSessionFromDataSource(ExecutorType execType,\nTransactionIsolationLevel level,\nboolean autoCommit)dss_factory - sm_transaction: color red创建tx\ntransactionFactory.newTransactionsm_transaction -- dss_factorydss_factory - config: color red创建Executor\nconfiguration.newExecutor(tx, execType)group #EEE 创建 Executorconfig - config: 根据 executorTyp\n初始化Batch/Reuse/Simple/CachingExecutorconfig - interceptor_chain: (Executor) pluginAll(executor)\ncolor red包括PageInterceptor、MetaObjectInterceptor等interceptor_chain - interceptor: interceptor.plugin(target)interceptor - interceptor: plugin(Object executor)interceptor - plugin: color redPlugin.wrap(target, this): 代理对象\ncolor red执行的handler是各类interceptorplugin -- configendconfig -- dss_factorydss_factory - ds_session: color red创建SqlSession\nnew DefaultSqlSession(configuration, executor, autoCommit)endendds_session -- ss_template方法的执行
ss_template - ds_session: method.invoke(sqlSession, args)group 具体method的执行ds_session - ds_session: selectList(String statement, Object parameter)ds_session - config: configuration.getMappedStatement(statement)config -- ds_sessionds_session - mstatement: sqlSource.getBoundSql()\ncolor red获取到databaseId的sqlmstatement -- ds_sessionds_session - bexecutor: executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER)group 拦截器执行bexecutor - plugin: invoke()plugin - interceptor: intercept()interceptor -- pluginplugin -- bexecutorendbexecutor - bexecutor: query()bexecutor - bexecutor: queryFromDatabase()bexecutor - bexecutor: prepareStatement()group #EEE 从连接池中获取连接bexecutor - bexecutor: getConnection()bexecutor - sm_transaction: transaction.getConnection()sm_transaction - sm_transaction: openConnectionsm_transaction - dr_datasource: dataSource.getConnection()dr_datasource - dr_datasource: getConnection()dr_datasource - dbc2_datasource: dataSourceMap.get(primary)dbc2_datasource -- sm_transactionsm_transaction -- bexecutorendbexecutor - shandler: handler.query(stmt, resultHandler)shandler -- bexecutorbexecutor -- ds_sessionendds_session -- mmethod事务的提交
ss_template - ds_session: sqlSession.commit(true)
ds_session -- ss_templatesession的关闭
ss_template - ds_session: closeSqlSession()
ds_session -- ss_templateendumlclass_baomidou.puml
startuml
skinparam linetype orthotitle 【动态数据源】类图 java
namespace javax.sql #EEE {interface Wrapper {unwrap(java.lang.ClassT iface): T TisWrapperFor(java.lang.Class? iface): boolean}interface CommonDataSource { getLogWriter(): PrintWriter setLogWriter(PrintWriter out): void setLoginTimeout(int seconds): void getLoginTimeout(): int getParentLogger(): Logger}interface DataSource {-- getConnection(): Connection getConnection(String username, String password): Connection}Wrapper |-- DataSourceCommonDataSource |-- DataSource
} spring
namespace org.springframework.beans.factory #EEE {interface InitializingBean { {static} afterPropertiesSet(): void}
}namespace org.springframework.jdbc.dataSource #EEE {abstract class AbstractDataSource {}note right: 实现了CommonDataSource的基本操作javax.sql.DataSource |.. AbstractDataSource
}baomidou
namespace com.baomidou.dynamic.datasource.ds #EEE {abstract class AbstractRoutingDataSource {# {abstract} determineDataSource(): DataSource# {abstract} getPrimary(): String getConnection(): Connection}org.springframework.jdbc.dataSource.AbstractDataSource |--- AbstractRoutingDataSource
}namespace com.baomidou.dynamic.datasource #EEE {abstract class DynamicRoutingDataSource {-- Override determineDataSource(): DataSource Override getPrimary(): String}com.baomidou.dynamic.datasource.ds.AbstractRoutingDataSource |-- DynamicRoutingDataSourceorg.springframework.beans.factory.InitializingBean |.. DynamicRoutingDataSource
}namespace com.baomidou.dynamic.datasource.provider #EEE {interface DynamicDataSourceProvider { {static} loadDataSources(): MapString, DataSource}abstract class AbstractDataSourceProvider {- defaultDataSourceCreator: DefaultDataSourceCreator- dynamicDataSourceProperties: DynamicDataSourceProperties--# createDataSourceMap(MapString, DataSourceProperty dataSourcePropertiesMap): MapString, DataSource}class YmlDynamicDataSourceProvider {- dataSourcePropertiesMap: MapString, DataSourceProperty-- Override loadDataSources(): MapString, DataSource}DynamicDataSourceProvider |.. AbstractDataSourceProviderAbstractDataSourceProvider |-- YmlDynamicDataSourceProvider
}namespace com.baomidou.dynamic.datasource.creator #EEE {interface DataSourceCreator { {static} createDataSource(DataSourceProperty dataSourceProperty): DataSource {static} support(DataSourceProperty dataSourceProperty): boolean}abstract class AbstractDataSourceCreator {# properties: DynamicDataSourceProperties# dataSourceInitEvent: DataSourceInitEvent {abstract} doCreateDataSource(DataSourceProperty dataSourceProperty): DataSource-- createDataSource(DataSourceProperty dataSourceProperty): DataSource}class DefaultDataSourceCreator {- creators: ListDataSourceCreator-- createDataSource(DataSourceProperty dataSourceProperty): DataSource}class BasicDataSourceCreator {- creators: ListDataSourceCreator--static {} Override doCreateDataSource(DataSourceProperty dataSourceProperty): DataSource Override support(DataSourceProperty dataSourceProperty): boolean}note left of BasicDataSourceCreator::staticbuilderClass Class.forName(org.springframework.boot.jdbc.DataSourceBuilder);builderClass Class.forName(org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder);end noteDataSourceCreator |.. AbstractDataSourceCreatorAbstractDataSourceCreator |-- BasicDataSourceCreator
}namespace com.baomidou.dynamic.datasource.spring.boot.autoconfigure #EEE {class DataSourceProperty {- type: Class? extends DataSource- driverClassName: String- url: String- username: String- password: String- druid: DruidConfig- dbcp2: Dbcp2Config...}note left of DataSourceProperty::druidNestedConfigurationPropertyend noteclass DynamicDataSourceProperties { {static} PREFIX: String- primary: String- strict: Boolean- datasource: MapString, DataSourceProperty- druid: DruidConfig- dbcp2: Dbcp2Config...}note left of DynamicDataSourceProperties::PREFIXvalue springframework.datasource.dynamicend noteclass DynamicDataSourceCreatorAutoConfiguration {-- dbcp2DataSourceCreator(): Dbcp2DataSourceCreator basicDataSourceCreator(): BasicDataSourceCreator dataSourceCreator(ListDataSourceCreator dataSourceCreators): DefaultDataSourceCreator}class DynamicDataSourceAutoConfiguration {- properties: DynamicDataSourceProperties- dataSourcePropertiesCustomizers: ListDynamicDataSourcePropertiesCustomizer-- ymlDynamicDataSourceProvider(): DynamicDataSourceProvider dataSource(): DataSource Override afterPropertiesSet(): void}com.baomidou.dynamic.datasource.DynamicRoutingDataSource --[hidden] DynamicDataSourcePropertiesDynamicDataSourceProperties - DataSourcePropertyDynamicDataSourceProperties -- DynamicDataSourceAutoConfigurationDynamicDataSourceAutoConfiguration - DynamicDataSourceCreatorAutoConfiguration: Import
}endumlclass_mybatis.puml
startuml
skinparam linetype orthotitle 【MyBatis】类图 java
namespace javax.lang #EEE {interface AutoCloseable {-- close(): void}
}namespace javax.io #EEE {interface Closeable {-- close(): void}javax.lang.AutoCloseable |-- Closeable
}namespace javax.lang.reflect #EEE {interface InvocationHandler {-- invoke(Object proxy, Method method, Object[] args): Object}
}namespace javax.sql #EEE {interface Connection {-- prepareStatement(String sql): PreparedStatement setSavepoint(): Savepoint setAutoCommit(boolean autoCommit): void rollback(Savepoint savepoint): void getTransactionIsolation(): int setTransactionIsolation(): void rollback(): void commit(): void Override close(): void}javax.lang.AutoCloseable |-- Connection
}spring
namespace org.springframework.context #EEE {interface ApplicationListener {-- onApplicationEvent(E event): void}
}namespace org.springframework.core.io #EEE {interface Resource {-- exists(): boolean isReadable(): boolean isOpen(): boolean getURL(): URL getFile(): File}
}namespace org.springframework.beans.factory #EEE {interface BeanFactory {-- getBean(ClassT requiredType): T isSingleton(String name): boolean isPrototype(String name): boolean}interface FactoryBeanT {-- getObject(): T}interface InitializingBean { {static} afterPropertiesSet(): void}
}ibatis
namespace org.apache.ibatis #EEE {interface SqlSession {-- getMapper(ClassT type): T getConfiguration(): Configuration getConnection(): Connection selectOne(String statement): T selectList(String statement): ListE select(String statement, ResultHandler handler): void insert(String statement): int update(String statement): int delete(String statement): int commit(): void rollback(): void Override close(): void}interface SqlSessionFactory {-- openSession(): SqlSession getConfiguration(): Configuration}class Configuration {# environment: Environment# objectFactory: DefaultObjectFactory# mappedStatements: MapString, MappedStatement}class SqlSessionTemplate {- sqlSessionFactory: SqlSessionFactory- executorType: ExecutorType- sqlSessionProxy: SqlSession, 代理的是 SqlSessionInterceptor}javax.io.Closeable |-- SqlSessionjavax.sql.Connection --[hidden] SqlSessionSqlSession .. SqlSessionFactory: openSession()SqlSessionFactory .. Configuration: getConfiguration()SqlSessionTemplate .| SqlSession}namespace org.apache.ibatis.binding #EEE {class MapperProxyFactory {- mapperInterface: ClassT- methodCache: MapMethod, MapperMethod-- newInstance(SqlSession sqlSession): T# newInstance(MapperProxyT mapperProxy): T}class MapperProxy {-- invoke(Object proxy, Method method, Object[] args): Object}class MapperMethod {-- execute(SqlSession sqlSession, Object[] args): Object}MapperProxyFactory .. MapperProxy: new MapperProxy()MapperProxy .. MapperMethod: mapperMethod.execute()
}namespace org.apache.ibatis.executor #EEE {interface Executor {-- update(MappedStatement ms, Object parameter): int query(MappedStatement ms, \nObject parameter, \nRowBounds rowBounds, \nResultHandler resultHandler, \nCacheKey cacheKey, \nBoundSql boundSql): ListE commit(boolean required): void rollback(boolean required): void getTransaction(): Transaction close(boolean forceRollback): void}org.apache.ibatis.binding.MapperMethod -- Executor}namespace org.apache.ibatis.plugin #EEE {interface Interceptor {-- intercept(Invocation invocation): Object plugin(Object target): Object setProperties(Properties properties): void}class Plugin {- target: Object- interceptor: Interceptor- signatureMap: MapClass?, SetMethod-- Override invoke(Object proxy, Method method, Object[] args): Object}javax.lang.reflect.InvocationHandler |-- PluginPlugin . Interceptor: Plugin.wrap
}namespace org.apache.ibatis.transaction #EEE {interface Transaction {-- getConnection(): Connection commit(): void rollback(): void close(): void}interface TransactionFactory {-- newTransaction(Connection conn): Transaction newTransaction(DataSource dataSource, \n TransactionIsolationLevel level, boolean autoCommit): Transaction}javax.sql.Connection .. Transaction: getConnection()Transaction .. TransactionFactory: newTransaction()
}namespace org.apache.ibatis.mapping #EEE {class Environment {- id: String- transactionFactory: TransactionFactory- dataSource: DataSource}interface DatabaseIdProvider {--setProperties(Properties p): voidgetDatabaseId(DataSource dataSource): String}class VendorDatabaseIdProvider {-- Override setProperties(Properties p): void Override getDatabaseId(DataSource dataSource): String- getDatabaseName(DataSource dataSource): String}DatabaseIdProvider |.. VendorDatabaseIdProvider
}mybatis
namespace org.mybatis #EEE {class SqlSessionFactoryBean {- configLocation: Resource- configuration: Configuration- mapperLocations: Resource[]- dataSource: DataSource- transactionFactory: TransactionFactory- sqlSessionFactoryBuilder: SqlSessionFactoryBuilder- sqlSessionFactory: SqlSessionFactory- plugins: Interceptor[]- databaseIdProvider: DatabaseIdProvider-- Override afterPropertiesSet(): void Override getObject(): SqlSessionFactory Override onApplicationEvent(ApplicationEvent event): void}note left of SqlSessionFactoryBean入口核心this.sqlSessionFactory buildSqlSessionFactory()end noteorg.springframework.beans.factory.FactoryBean |.. SqlSessionFactoryBeanorg.springframework.beans.factory.InitializingBean |.. SqlSessionFactoryBeanorg.springframework.context.ApplicationListener |.. SqlSessionFactoryBean
}enduml写在后面 如果本文内容对您有价值或者有启发的话欢迎点赞、关注、评论和转发。您的反馈和陪伴将促进我们共同进步和成长。 系列文章
【UML】- 类图 【GitHub】- design-pattern设计模式 【连接池】-从源码到适配上你遇到过数据库连接池的问题吗This connection has been closed 【连接池】-从源码到适配下使用dynamic-datasource导致连接池没生效升级版本