spring-mybatis

对我来说,mybatis有几个主要核心模块吧。包括:插件(Plugin)、缓存、动态sql解析,这几个是比较难理解的部分。

加载项目的时候会把mybatis里面的sql解析成一个个的MapperedStatement,里面呢包含一系列的SqlNodel,比如WhereSqlNode,IfSqlNode,在具体执行解析sql的时候,会由SqlNode一步步进行解析(采用了责任链和装饰器模式,一层包着一层,递归解析。),最后拼接成目标要执行的sql。并且将这次查询的statementId,参数等信息封装到缓存当中,如果开启了缓存的话。这些解析的信息最后都会放到一个大的Configuration对象中去。

首先插件主要是基于责任链模式和动态代理的方式对要执行的sql进行增强处理的,比如分页插件。当执行sql的时候,执行器会识别到要做增强的插件,换句话说就是一个拦截器,执行前会先执行插件中得代码逻辑,然后再由Executor执行具体的sql。

然后就是缓存咯,缓存主要用到责任链+装饰器模式,我记得主要有 最原始的一个缓存,然后LRUCache,LogCache,SynchronizedCache等等,一步步调用封装。

 

Mybatis 集成 Spring:

1. 集成SqlSessionFactoryBean是干嘛的,就是用来构建SqlSessionFactory,,用来读取Mybatis的信息设置到configuration中。

2. 怎么集成spring的声明式事务,实际上就是拿到spring的声明式事务,开启事务时,创建一个connection,放在TransactionSychronizationManager.resources中 ... 在构建SqlSessionFactoryBean时,会new一个mybatis-spring适配的一个事务工厂类:SpringManagedTransactionFactory,当mybatis获得Connection就会从这个适配SpringManagedTransaction.getConnection中去获得Connection (这个Connection实际上就是TransactionSynchronizationManager中的Connection)。

 

怎么让Spring去管理Mapper代理?

我们都知道Mapper最后真正的对象都是代理类,是基于jdk代理的。

除了用已经知道的FactoryBean方式去加载Mapper代理,还可以通过@Import的方式自定义BeanDefinitionRegistry的注册Bean定义的逻辑,但这个要求Spring的版本在4.0之后了。还有另外一种方式就是实现BeanDefinitionRegistryPostProcessor接口,然后在方法postProcessBeanDefinitionRegistry()方法中:

BeanDefinitionScanner.doScan 重写isCandidateComponent()方法,去除不扫描接口和抽象类的逻辑。

spring加载的时候会调用invokeBeanFactoryProcessor(beanFactory)方法,

 

 扫描的问题解决了,那么由于没有实例化对象,还是不能创建Bean交个spring容器进行管理,那么就需要创建代理对象,交给Spring容器进行管理了。

怎么创建,在哪里创建呢?

第一种方案:在BeanPostProcessor中做判断,比如只给Mapper包下面的接口创建动态代理,加上这么一个判断。

第二种方案:偷天换日,用FactoryBean去生成真正的Bean对象。

 

 第三种方法:beanDefinition.setFactoryMethodName();

但是静态工厂方法要求传参,class类型,怎么传递呢?如下:

 

 也可以通过属性注入把Mapper接口传进到FactoryBean中。

 

但是要引入SqlSessionFactory,所以要注入到这个BeanDefinitionRegistryPostProcessor中来。通过修改注入类型做到。

但是SqlSessionFactory在spring容器中是SqlSessionFactoryBean。但是因为该类实现了FactoryBean接口,通过调用getObjectType来了个狸猫换太子。

 

 

 

最后就是注册BeanDefinition了。

 源码流程和上面其实类似。

 End!

 

posted @ 2022-11-30 17:51  君莫笑我十年游  阅读(100)  评论(0编辑  收藏  举报