Mybatis+Spring整合源码

Mybatis如何整合Spring?

/*********Mybatis如何整合Spring?/ 一、mybatis如何初始化? 加入这个注解,
1.@MapperScan(“com.luban.mybatis.service.mapper”) 进入注解可以看到MapperScannerRegistrar类型.
2.@Import(MapperScannerRegistrar.class) 此类实现了ImportBeanDefinitionRegistrar类,此类通过实现的方法,在注入beanMap都时候,进行调用实现的方法.
3.MapperScannerRegistrar implements ImportBeanDefinitionRegistrar org.mybatis.spring.annotation.MapperScannerRegistrar#registerBeanDefinitions()
Spring中调用这个方法,把需要注入Spring的Mbatis的类进行创建并注入到beanMap中去.
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
4.调用doScan方法进行包扫描,然后把扫描出来类进行赋值需要如何注入已经它的实现类 org.mybatis.spring.mapper.ClassPathMapperScanner#doScan
5.调用父类中的doScan方法,这里是扫描包,并拿到指定包下面的所有类 (1)首先拿到当前包路径------>根据包路径找到运行时的classPath的路径.因为在运行环境中只有classPath路径才能拿到类型------>根据classPath路径拿到下面所有的类的classPath路径------>封装到Set中----->解析后放到beanMap中.
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
6.拿到所有的包下面的类,进行赋值,这里赋值的是需要如何注入和其他一些属性.构造方法等等(addToConfig,mapperFactor Bean,构造设置传入当前接口).
(1)构造设置传入当前接口:这里非常重要:
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
这里其实就是把当前扫描出来的接口通过构造方法注入到mapperFactorBean类型的mapperInterface属性中去了.在后面实例化mapperFactorBean类的时候可以直接拿到接口,然后解析接口中的信息,执行SQL语句.
设置完值以后是怎么重新放到beanMap中去的呢?其实这里是一个循环,循环出来的类可以直接对其赋值,赋值也就是改变了这个beanMap当中的这个对象的值了.
org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions
7.重点:这里把Mapper层赋值到beanMap中去,是放在beanNameList中的最后的.因为这里用的是List集合,List数组是有序的,先插入的先出来,后插入的后出来.一个栈,先进先出后进后出.
到此Mybatis整合spring初始化完成. 二、怎么实例化注入扫描出来的接口和MapperFactoryBean类的呢?
通过构造方法实例化MapperFacotryBean开始…
只要有一个类需要去注入属性那么就会进入这个方法,往这个Map中去注入值.
Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
这个是开始方法.一开始会进行某一个类的属性注入的时候就会进入这个方法.进入这个方法以后,会进行循环所有的bdMap中的类,然后判断其中实现了FacotryBean的接口,然后进行实例化.MapperFacotryBean就是实现了的.所以就会实例化.
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeanNamesForType()
这个方法是去new出来MapperFactoryBean类型,名称是Mapper,类型是MapperFactoryBean.这里只是new了一个bd还没有进行实例化.
1.org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition
这个方法中去bdMap中拿去出来已经在Mybatis初始化时set到bd中的MapperFactoryBean的路径包名.
2.org.springframework.beans.factory.support.DefaultListableBeanFactory#getBeanDefinition
具体实现的方法在这个方法中.
3.org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefinition(java.lang.String,
org.springframework.beans.factory.config.BeanDefinition,
org.springframework.beans.factory.config.BeanDefinition)
在这个方法中,去判断当前类具体的是否实现了FactoryBean,如果实现了那么就会修改isFactoryBean的状态为true.
4.org.springframework.beans.factory.support.AbstractBeanFactory#isFactoryBean()
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) { Boolean result = mbd.isFactoryBean; if
(result == null) { Class<?> beanType = predictBeanType(beanName,
mbd, FactoryBean.class); 这个地方直接判断,然后如果是实现了FactoryBean的返回true
result = (beanType != null &&
FactoryBean.class.isAssignableFrom(beanType));
这里直接给isFactoryBean赋值为true mbd.isFactoryBean = result; }
return result; }

//隔离提示
在对于spring内置的类进行实例化的时候,不会对Mybatis中的mapper进行实例化创建,因为这里会设置为false.只有当实例化自己创建的类的时候才会进行实例化mapper中的数据,这里为true.
postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,
true, false);

继续往下走: 通过下面四个步骤进行实例化MapperFacotryBean.
1.org.springframework.beans.factory.support.AbstractBeanFactory#isTypeMatch(java.lang.String,
org.springframework.core.ResolvableType, boolean)
2.org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean(java.lang.String,
org.springframework.beans.factory.support.RootBeanDefinition, boolean)
3.org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getSingletonFactoryBeanForTypeCheck
具体看这个方法中的创建实例化对象.也就是通过MapperFacotryBean的构造方法实例化MapperFactoryBean.
4.org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
当在实例化其他类的时候,会进行MapperFacotryBean的实例化,因为他是实现了FactoryBean.在实例化MapperFactoryBean的时候呢,会进行拿去他的构造方法,我们前面设置了构造方法的参数,那么这里实例化的时候就直接会进行传入这个参数了.然后把这个类进行实例化出来.
在进行实例化MapperFacotryBean的时候,把设置到mbd中的值拿去出来,也就是在构造方法中set进去的mapper层数据.
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());//这里放进去的.其实就是PayServiceImplMapper接口.
ConstructorArgumentValues cargs =
mbd.getConstructorArgumentValues();//这里拿出来 这个Map是在这里赋值的,put的.
ConcurrentMap<String, BeanWrapper> factoryBeanInstanceCache = new
ConcurrentHashMap<>();
5.org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#factoryBeanInstanceCache
放入到这个Map中代表,通过构造方法实例化MapperFacotryBean成功,只是名字还是原来的mapper层的名称而已…
在这里插入图片描述
如果给实例化后的MapperFacotryBean进行注入属性的呢?
service层通过属性注入把Mapper层注入进去的时候执行了MapperBeanFacotry的属性注入.
流程是:大体流程,明天细化
1.首先先进行实例service层的类,然后进行service层类的数组注入,在注入属性的时候.会拿去到当前类名称和包名+方法名.通过后续创建这个mapper层的时候,从上面已经实例化好的MapperFactoryBean中拿去出来.就不用在进行去实例化了.
在这里插入图片描述
然后进入下面这个方法中去进行属性的注入:
在这里插入图片描述
然后因为一开始初始化Mybatis的时候已经设置过了,必须要通过set方法注入,也就是通过byType进行注入.所以后面会去找他的父类中的属性类型,因为一开始就已经在@bean的时候注入了,所以这里就直接从中拿去出来就可以了.然后就会通过方法注入的形式注入到MapperFacotryBean中去.

注入完成属性之后会调用这个方法
在这里插入图片描述
然后调用这个方法.这个方法回去执行实现了InitializingBean的afterPropertiesSet()方法.通过这个方法也就是去执行了MapperFacotryBean当中afterPropertiesSet()方法,但是这里是一开始先调用父类的这个方法,然后在调用MapperFacotryBean中的这个方法.这个方法的执行主要就是为了拿去到通过构造方法传入过来的接口中的方法上面加的注解中的值.如果是通过xml来读取的话,这里也会直接读取到SqlFacotryBean中设置的路径然后通过包名+方法名称去遍历出来放到一个map中去.这个map中存放了key:包名+方法名。value:已经封装好了的对象

当要通过service去执行的时候,其实也就是拿去代理对象MapperFacotryBean的getBean()方法,然后通过这个方法就会去执行invoke方法(),然后拿取出来这个包名+方法名的map拿去出来,这个地方拿去出来的对象是已经封装好了sql,参数,方法名的.然后在直接执行sql就行了

在这里插入图片描述
在这里插入图片描述

其实就是代理,Mapper包下面的接口全是代理对象,进行调用里面的方法.
org.mybatis.spring.mapper.ClassPathMapperScanner#doScan
org.mybatis.spring.mapper.ClassPathMapperScanner#mapperFactoryBean
org.mybatis.spring.mapper.MapperFactoryBean
org.mybatis.spring.mapper.MapperFactoryBean#getObject----->org.mybatis.spring.mapper.MapperFactoryBean#mapperInterface:这个是SqlSessionTemplate类中的方法.
org.mybatis.spring.SqlSessionTemplate#getMapper
org.apache.ibatis.session.Configuration#getMapper
org.apache.ibatis.binding.MapperRegistry#getMapper
org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)
//最后到这个方法了. protected T newInstance(MapperProxy mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),
new Class[] { mapperInterface }, mapperProxy); } 最后Mybatis执行了代理对象中的方法.
org.apache.ibatis.binding.MapperProxy#invoke
MapperMethod类:就是和bean的BD一样,描述一个方法.就是当前的方法.mapperMethod中就包含了方法的所有信息,包括SQL语句,等等。
final MapperMethod mapperMethod = cachedMapperMethod(method);
execute()方法:就是判断你是Insert,还是UpDate,还是delete,还是select.然后根据上面获取的方法信息中的value值,得到具体要执行的.就执行了.
return mapperMethod.execute(sqlSession, args);

org.apache.ibatis.binding.MapperMethod#execute
org.apache.ibatis.binding.MapperMethod#executeForMany:这里是一个代理对象.看不到代理对象的源码.所以你只能看到invoke中.具体的逻辑看不到了.当执行完以后代理的方法后,就会走下面了.
org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor:这个类中,就把session关闭了.:这里使用的是SqlSessionTemplate类中的方法.
/*********Mybatis如何整合Spring?/

不管是什么类,只要是实例化属性,那么进入这个方法就会去创建MapperFacotryBean然后放入到Map中.

图一在这里插入图片描述
图二在这里插入图片描述
图三在这里插入图片描述
图四在这里插入图片描述
图五

同一类中开始在这里插入图片描述
在这里插入图片描述
同一类中结束

图六
在这里插入图片描述
图七在这里插入图片描述
图八:这个地方就是通过构造方法去创建你想要创建的类在这里插入图片描述
找到构造方法进入这里

图九在这里插入图片描述
拿到之前已经初始化时候设置的mapper层接口的类型

图十
在这里插入图片描述
然后通过接口的类型,去创建者类型.

图十一![在这里插入图片描述](https://img-blog.csdnimg.cn/20210208163243893.png请添加图片描述
这个地方会传入进来已经设置好的Mapper层的接口然后返回出去.

图十二在这里插入图片描述
进入这个方法,把参数类型拿到,把MapperFacotryBean拿到.在这里进行执行构造方法了.

图十三在这里插入图片描述
图十四在这里插入图片描述
图十五在这里插入图片描述
到这里通过反射把当前类型然后参数传入构造方法中创建出来对象.开始返回

图十六在这里插入图片描述
到这里放到map中创建成功了.这个代码是和图八步骤中的代码为同一方法中的代码.

图八是开始创建,图十七是等待图八创建完对象以后放入到map中去了.

图十七:在这里插入图片描述
插入解释:

在第一次实例化MapperFacotryBean后,如果后续进入的时候,会判断这个facotryBeanInstanceCache的Map中是有已经实例化了当前传入的,如果实例化了那么就不会在往下走了,也就是说实例化MapperFacotryBean的Mapper只会执行一次.

图十八
在这里插入图片描述
第二步:实例化成功以后开始属性注入:

如何触发这个属性的注入呢?(两种方法)

1、可以通过实例化Service层中PayServiceImpl类时.在注入属性的时候创建出来PayServiceImplMapper接口的MapperFacotryBean

@Service
public class PayServiceImpl{ 
@Autowired   
PayServiceImplMapper payServiceImplMapper;   
@Autowired  
PayServiceImplMapper1 payServiceImplMapper1;
}

2、可以通过直接实例化PayServiceImplMapper的时候,然后去注入MapperFacotryBean的属性.

这里是把扫描路径下中的所有类在bdMap中存放的bd,因为之前在初始化Mybatis的时候,就已经把PayServiceImplMapper类放入到了bd中了.还给这个类设置了MapperFacotryBean.实现了FacotryBean.所有这里会进入getBean()方法中.

图十九
在这里插入图片描述
图二十:在这里插入图片描述图二十一:

在这里插入图片描述
图二十二:在这里插入图片描述
图二十三:

这里就是把实例化成功的MapperFacotryBean的类后放入到factoryBeanInstanceCache的Map中的类拿出来.如果有那么就拿出来,然后移除掉,如果没有那么这里就返回为null了.这里就不用创建了,而只是为了这个实例化好的类进行属性的填充.这里就把名为PayServiceImplMapper,类型为MapperFacotryBean的类型拿出来.并且移除掉Map中名为PayServiceImplMapper的类型,之后就是进行对于名为PayServiceImplMapper,类型为MapperFacotryBean的类型进行属性填充.

这个factoryBeanInstanceCache集合是在图十七放入的,这里判断拿去出来.在这里插入图片描述
图二十四

这里执行PaySessionImplMapper的

1.先进入populateBean()方法--------->属性注入---------->此处有set()方法注入,之前是在初始化Mybatis的时候赋值的通过Bytype注入的

​ (1)属性注入方式,注解@Autowired注入.

​ (2)属性注入方式,set()方法注入.

2.再进入initializeBean()方法中

​ (1)执行方法类中实现了BeanPostProcessors接口的befor方法和after方法.

​ (2)执行方法类中实现了InitializingBean接口的afterPropertiesSet()方法在这里插入图片描述
现在开始解释属性注入: populateBean方法中

autowireByType:这里是之前在初始化MapperFacotryBean的时候就设置了AutowireMode为2,也就是设置了通过ByType设置属性.也就是根据set方法中参数类型来注入.

图二十五:

在这里插入图片描述
这个方法就是去创建当前set方法中参数的类型.创建出来以后,会在后续通过set方法把此类型注入到MapperFacotryBean中.这里其实也就是去找SqlSessionFacotryBean类型.并且把这个类型创建出来.然后才能进行set

图二十六
在这里插入图片描述
图二十七在这里插入图片描述
图二十八
在这里插入图片描述
图二十九
在这里插入图片描述后面会去创建SqlSessionFactoryBean这个类型.这个类型是之前在Appconfig配置文件中通过@Bean注解放入容器当中的,只是放入了bdMap中,并没有实例化放入ObjectMap中.所以这里需要去创建SqlSessionFactoryBean.然后放到ObjectMap中,那么是如何去创建的呢?

图三十:这里会去ObjectMap中找,但是为null.

在这里插入图片描述
在这里插入图片描述
到此为止已经拿到set方法中的参数类型创建成功的类型对象了.就开始返回了.返回到图二十五处,继续往下走.

图三十一:这里去创建SqlSessionFacotryBean类.创建出来以后会直接放到ObjectMap中.
在这里插入图片描述

图三十二:
这里去创建SqlSessionFacotryBean,并且把创建好的bean放入到ObjectMap中去了.以后所有的sqlFacotryBean都可以直接拿取出来了.
在这里插入图片描述
图三十三:在这里插入图片描述
图三十四:这里就是去创建SqlSessionFacotryBean类型了.
在这里插入图片描述
图三十五:如果此类型是由Application的Java配置类中@Bean注解创建的bean会进行这个方法,很明显SqlSessionFacotryBean是在ApplicationJava配置文件中@Bean注解创建的.
在这里插入图片描述
图三十六:这里去拿到@Bean方法中传入的参数类型,要通过这个传入参数进行new出SqlSessionFacotry.所以这里需要去创建方法传入的参数类型才行.这里@Bean方法的类型是DataSource,这里就需要去创建DataSource类型.
在这里插入图片描述
图三十七:这里去创建DataSource类型.
在这里插入图片描述
图三十八:
在这里插入图片描述
图三十九:去创建dataSource.
在这里插入图片描述
图四十:这里调用getBean()方法.
在这里插入图片描述
图四十一:从ObjectMap中去判断是否有DataSource类型,如果有那么直接就拿出来,如果没有那么就去创建,这里很明显没有,因为第一次进入这里是不可能存在已经创建好DataSource类型的.
在这里插入图片描述
图四十二:创建DataSource类
在这里插入图片描述
图四十三:这里去创建好DataSource后放入到ObjectMap中去.
在这里插入图片描述
图四十四:这里会去创建DataSource类型
在这里插入图片描述

这里就是去创建DataSource了

图四十五:
在这里插入图片描述
图四十六:在这里插入图片描述
这里Application类中@Bean注解方法上的类型参数是否存在,如果不存在了那么就进入这个,如果存在那么就会去创建这个类型,然后在执行setBeanInstance()方法中的instantiate()方法

图四十七:在这里插入图片描述
这里就是去执行了

图四十八:在这里插入图片描述
这里就是去执行Application中的@Bean注解的方法,并且把这个方法中new出来的类型对象返回回来.

图四十九:

在这里插入图片描述
这里是使用的CGLIB代理,因为配置类中加了@Configuration注解代表这个类型是CGLIB代理对出来的代理对象,这里执行的方法也是执行代理对象中的dataSource()方法,把这个DataSource直接new出来然后返回回来.

图五十:
在这里插入图片描述
到这里为止,创建好了DataSource类型,那么就开始返回了,也就是说图三十六那里开始创建的@Bean注解参数类型DataSource创建好了.这里返回到图三十六处继续继续去执行Application配置类中SqlSessionFacotryBean方法,把SqlSessionFactoryBean创建出来.再次之前会把创建好的DataSource放入到ObjectMap中去.

图五十一:

DataSource类型

1.先进入populateBean()方法--------->属性注入-------->此处DataSource类型没有属性

2.再进入initializeBean()方法中

​ (1)执行方法类中实现了BeanPostProcessors接口的befor方法和after方法.

​ (2)执行方法类中实现了InitializingBean接口的afterPropertiesSet()方法
在这里插入图片描述
图五十二:

此处对应图四十三,这里已经把DataSource创建完毕了,这里放入到ObjectMap中去了.在这里插入图片描述
图五十三:

此处对应图三十六,是同一个类中同一个方法中的代码.DataSource创建完之后返回到图三十六,拿到@Bean方法放创建好的参数类型.进入SqlSessionFacotryBean()方法中,获取SqlSessionFacotryBean创建new出来的实例.在这里插入图片描述
图五十四:在这里插入图片描述
图五十五:

此处就是把Application的Java配置类中的@Bean注解方法SqlsessionFactoryBean()进入进去new出SqlSessionFacotryBean,并且把MapperXML配置路径下面的所有MapperXML的路径+名称都拿到,放到SqlSessionFacotryBean类型的属性中.创建完成SqlSessioinFacotryBean后返回回来.在这里插入图片描述
图五十六:

此处调用CGLIBmethodProxy代理调用invokeSuper方法.执行Application中的SqlSessionFacotryBean()方法在这里插入图片描述
图五十七:

此处把SqlSessionFacotryBean拿到,并且把配置xml路径下的所有名称+xml都拿到了.在这里插入图片描述
图五十八:

SqlSessionFacotryBean类型

1.先进入populateBean()方法--------->属性注入-------->此处SqlSessionFacotryBean类型是没有属性的.

2.再进入initializeBean()方法中

​ (1)执行方法类中实现了BeanPostProcessors接口的befor方法和after方法.

​ (2)执行方法类中实现了InitializingBean接口的afterPropertiesSet()方法---------->有afterPropertiesSet()方法在这里插入图片描述
图五十八:在这里插入图片描述
图五十九:

这里执行了SqlSessionFacotryBean的afterPropertiesSet()方法.

此处这个SqlSessionFacotryBean大有来头,可是比较重要的一个方法了.主要是去拿去刚刚创建SqlSessionFacotryBean类的时候set的Resource的xml路径下面的SQL语句和参数类型,返回值类型,包名,方法名称等信息.并且存放到Map中.在这里插入图片描述
图六十:

这里也就执行了afterPropertiesSet()在这里插入图片描述
图六十一:

这里是一个for循环其中this.mapperLocations也就是在@Bean注解中实例化SqlSessionFacotryBean类型的时候set进去的xml文件的全路径.在图五十七的时候,解析写入的文件路径下面所有的xml文件路径,只是拿到文件路径.然后放到Resource中去了.再把Resource放到mapperLocations的集合中去(sqlSessionFactoryBean.setMapperLocations(resources)😉.在这个循环中用于解析.

这里也就是xml文件有多少这个地方就会解析多少.把所有的都解析出来后

放入到Map<String, MappedStatement> mappedStatements = new StrictMap中.

后面再执行代理类中的invoke方法的时候,匹配这个集合中的sql信息,执行sql语句.

创建出XMLMapperBuilder类型,用于parset()解析以后放到这个类型的属性中.在这里插入图片描述
图六十二:

configurationElement(parser.evalNode(“/mapper”));此方法就是去拿去这个xml并且拿到xml中所有的sql所有的信息组成对象放到Map当中.在这里插入图片描述
图六十三:

这是xml中的数据
在这里插入图片描述
此方法就是去拿去xml中的namespace,insert,id,parameterType和SQL语句.
在这里插入图片描述
图六十四:

此处就是把上面解析出来的List list进行解析.这里是list类型因为xml中有很多标签中存放不同的id.解析xml中的时候.根据不同的id会解析出非常多的list.因此这里要用list存放.在这里插入图片描述
图六十五;

此方法中去循环解析.在这里插入图片描述
图六十六:在这里插入图片描述
图六十七:在这里插入图片描述
图六十八:

此方法就重要了,此方法是把从xml中解析出来的sql的所有信息翻到mappedStatement类型中去了.然后这里的

key:ms.getId()是:com.luban.mybatis.service.mapper.PayServiceImplMapper.insert.

value:MappedStatement ms

放入到Map<String, MappedStatement> mappedStatements = new StrictMap中.在这里插入图片描述
因为图六十五是for循环,所以会继续执行.list中有的话会继续.没有的话就会走到图六十二中的第二个方法.bindMapperForNamespace()在这里插入图片描述
图六十九:

进入这个方法中.在这里插入图片描述
图七十:

这里放入knownMappers的Map中是为了后面在判断是否这个类型解析过了用的.然后进入parser.parse()方法中.在这里插入图片描述
图七十一:

此parse()方法中重要:使用来解析接口的所有信息的,必须是否加了二级缓存注解,是否加了@CacheNamespaceRef注解,是否没有解析到当前类的xml.接口中的多个方法解析.

(1)loadXmlResource();在这里插入图片描述
(2)parseCache();

判断是否加了@CacheNamespace二级缓存注解,如果加了那么就开启缓存功能模式.在这里插入图片描述
(3)parseCacheRef();

判断是否加了@CacheNamespaceRef注解,如果加了开启.在这里插入图片描述
(4)Method[] methods = type.getMethods():获取当前接口的中的所有方法.进行遍历判断是否已经解析过了.

进入parseStatement()方法中在这里插入图片描述
图七十二:

这里把当前接口中的当前方法判断是否加了注解,如果加了注解那么就拿去当前注解的value值.也就是sql语句.如果是没有加注解的方法,那么就会返回null.在这里插入图片描述
图七十三:

这里把刚刚拿到的sql的所有信息封装到对象中.在这里插入图片描述
图七十四:

放入到mappedStatements的Map中去.代表解析过了这个方法.在这里插入图片描述
把图六十一循环解析完毕以后那么SqlSessionFacotryBean的afterPropertiesSet()方法也就结束了.回到图五十九中继续往下执行了.也就是开始返回了.

图七十五:

这里也就把SqlSessionFcaotryBean放入到ObjectMap中去了在这里插入图片描述
图:七十六:

在这个方法中去执行实现了FacotryBean接口类的getObject方法.然后返回回来放到bean中在这里插入图片描述
图七十七;

这里执行的时SqlSessionFacotryBean的getBean()方法。

如果这个实现了FacotryBean的类已经放到了ObjectMap中,那么会进入这个if语句中执行

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

也是一样的执行getObject方法.在这里插入图片描述
图七十八:在这里插入图片描述

图七十九:在这里插入图片描述

图八十:在这里插入图片描述

图八十一:在这里插入图片描述

图八十二;在这里插入图片描述
这里执行完SqlSessionFacotryBean类中的getBean()方法后继续返回。图二十五中继续执行

返回到创建名为PayServiceImplMapper,类型为MapperFacotryBean的父类set方法的SqlSessionFacotryBean类型。需要注入父类方法中。

返回到图二十五种继续执行。这里已经拿到了创建号的SqlSessionFacotryBean和DataSource。这里需要需要SqlSessionFacotryBean。

图八十三:

进入这个方法种,因为pvs不等于null。已经通过byType类型创建出来SqlSessionFacotryBean类型。并且也放到ObjectFacotryBean种。

这个方法主要的作用就是把创建出来SqlSessionFactoryBean类,通过MapperFacotryBean父类种的SqlSessionDaoSupport的setSqlSessionFactory方法根据byType注入。

public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {  
    if (!this.externalSqlSession) {   
    this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);  
    }
}

在这里插入图片描述
图八十四:

这里时for循环,因为set方法不止一个。所以这里时一个list集合的for循环。会把每一个set方法都注入进去。把循环出来pv放到deepCopy集合中去了。deeCopy.add(pv)在这里插入图片描述
图八十五:在这里插入图片描述
图八十六:

在这里把图八十四中循环到deepCoyp集合中的set方法循环出来,进行set方法注入。因为set方法不止一个,所以这里要循环。且时PropertyValue类型。在这里插入图片描述
图八十七:

这里判断tokens是否为null。为null走else中的set注入,不为空走nestedPa中的set在这里插入图片描述
图八十九:在这里插入图片描述
图九十:在这里插入图片描述
图九十一:

在这里执行invoke方法也就是执行了当前类的set方法,并且把类型注入到这个set方法中。在这里插入图片描述
图九十二:

setSqlSessionFacotry()方法

此处也就对应了图八十三。通过set方法注入属性类型了。在这里插入图片描述
此处注入完毕以后还是回退了。回退到图二十四中执行第二步方法了,因为第一步注入属性执行完了,所以这里开始执行名为PayServiceImplMapper,类型为MapperFacotryBean的initializeBean()方法,其中有实现了beanPost接口的after方法和befor方法,还有执行其实也就是去执行invokeInitMethods()方法中实现了InitializingBean接口的afterPropertiesSet()方法。

图九十三:在这里插入图片描述
图九十四:在这里插入图片描述
图九十五:

这里就是执行MapperFactoryBean中的afterPropertiesSet()方法,但是MapperFactoryBean父类中有afterPropertiesSet()方法,所以就要先执行父类中的afterPropertiesSet()方法。在这里插入图片描述
图九十六:

DaoSupport类是MapperFactoryBean的父类,所以这里执行DaoSupport类的afterPropertiesSet()方法在这里插入图片描述
图九十七:

如何调到这个方法的呢?
因为图九十六中调用checkDaoConfig()方法,也就是执行了子类的checkDaoConfig()方,所有到了MapperFactorybean中的checkDaoConfig()方法中了。
configuration.hasMapper(this.mapperInterface)
这里是去判断之前初始化Mybatis的时候传入的接口类型PayServiceImplMapper是否已经在之前SqlSessionFactoryBean实例化的时候,执行SqlSessionFactoryBean中的afterPropertiesSet()方法执行的时候,放入到configuration方法下的knownMappers的Map去中没有。没有的话会在这里进行解析。SqlSessionFacortyBean中的afterPropertiesSet()方法是去解析xml配置文件后,再去解析接口中的方法。他不会去解析Mapper层中的所有接口,只是去解析配置在SqlSessionFacotoryBean中的xml路径下的所有xml,但是有些Mapper接口没有xml配置文件,所以解析不完整。因此这里会把Mybatis初始化时候传入的Mapper接口到这里判断一下,如果此Mapper没有xml配置文件那么会在这里进入进行解析。
那么这个knownMappers的Map是在什么时候放入的呢? 请看图七十,是在图七十放进去的。
在这里插入图片描述
到此为止也就把名为PayServiceImplMapper,类型为MapperFacotryBean实例化出来了,属性注入了,afterPropertiesSet()方法执行完毕了。接下来会继续沿着:图二十四图片中处继续往下走。往下走也就是把创建好的名为PayServiceImplMapper,类型为MapperFacotryBean放入到ObjectMap中去了。这个名为PayServiceImplMapper,类型为MapperFacotryBean是之前图一到图十七过程中就已经创建出来的。只是这里要放到ObjectMap中去了。

放进去后就回去执行名为PayServiceImplMapper,类型为MapperFacotryBean的getObject()方法了.

图:九十八在这里插入图片描述
图九十九:

此方法就非常重要了。是创建MapperFacotryBean的代理类。这个代理类中的invoke方法会去执行sql语句。在这里插入图片描述

图一百:在这里插入图片描述
图一百零一:在这里插入图片描述
图一百零二:

这里会把创建好的代理类对象放到factoryBeanObjectCache的Map中去,相当于一个缓存中,如果下次再来创建这个代理对象的时候就会先去这个factoryBeanObjectCache的Map中去找,找到了就不再需要创建。没有找到那么还需要创建。在这里插入图片描述
图一百零三:在这里插入图片描述
图一百零四:

到这里也就调用了MapperFacotryBean中的getObject()方法了。在这里插入图片描述
图一百零五:

这里也就是进入的SqlSessionTemplate类中的getMapper。在这里插入图片描述
一百零六:在这里插入图片描述
图一百零七:
在这里插入图片描述
图一百零八:

先调用了newInstance(SqlSession sqlSession)方法,new出来MapperProxy类,这个类实现了InvocationHandler接口,也就有invoke方法。在new MapperProxy的时候会进入MapperProxy的构造方法中,那么在创建这个代理类的时候就会用到。在执行MapperProxy类中invoke方法的时候也会用到这些属性了。

public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {  
    this.sqlSession = sqlSession;  this.mapperInterface = mapperInterface;  this.methodCache = methodCache;
    }

然后传入到newInstance(MapperProxy mapperProxy)方法中。把new出来的MapperProxy放到了Proxy。newProxyInstance方法中创建出来代理对象。那么这个代理对象就会执行MapperProxy类中的invoke()方法。完毕。

到这里也就执行完了名为PayServiceImplMapper,类型为MapperFactoryBean的getObject方法了。并且创建出来了代理类bean。这个代理类bean是注入给PayServiceImpl中的属性,并没有把这个bean放入到ObjectMap中去。可以看之前图九十八,已经把名为PayServiceImplMapper,类型为MapperFactoryBean放入到ObjectMap中了。所以后面如果还有service层需要注入mapper层的接口的话,那么就一定会走下图了。因为已经放到ObjectMap中了,然后把ObjectMap中创建好的实例,执行getObject创建出代理对象赋值给service层。
在这里插入图片描述
到这里也就执行完了名为PayServiceImplMapper,类型为MapperFactoryBean的getObject方法了。并且创建出来了代理类bean。这个代理类bean是注入给PayServiceImpl中的属性,并没有把这个bean放入到ObjectMap中去。可以看之前图九十八,已经把名为PayServiceImplMapper,类型为MapperFactoryBean放入到ObjectMap中了。所以后面如果还有service层需要注入mapper层的接口的话,那么就一定会走下图了。因为已经放到ObjectMap中了,然后把ObjectMap中创建好的实例,执行getObject创建出代理对象赋值给service层。

图一百零九在这里插入图片描述
**插入讲述:**上面到图一百零九跑完了整个流程.创建名为PayServiceImplMapper,类型为MapperFactoryBean的流程.并且创建好了SqlSessionFacotry,创建好了DatSource.创建好了MapperFacotryBean的代理对象,除了代理对象其他创建好的类型都放到了ObjectMap中去了.

下面是演示当另一个类来注入PayServiceImplMapper的流程.

图一百一十:

会在这个方法中去判断需要注入的Mapper是否已经创建了,如果已经创建了那么就不会再去创建了。但是会进入图一百零九中,执行getObject()方法。

在这里插入图片描述

当service层要注入Mapper层的时候,第二次去创建SqlSessionFacotryBean的时候,会直接找出来,然后判断它不是class类型了。因为已经是一个对象了。就是已经创建过了。
在这里插入图片描述

下面开始用代理类去调用SQL执行.

图一百一十二:

第一步:一、final MapperMethod mapperMethod = cachedMapperMethod(method);

​ 作用是拿去之前在图七十四把xml中sql信息解析出来通过key:包名+方法名,value:sql的所有信息(id,返回类型,参数,sql语句等等)放入到mappedStatements集合中.这里通过代理类执行sql语句的时候就需要去拿去出来sql的信息.所以代理类中直接可以拿到当前调用方法的包名+方法名.然后去mappedStatements集合中通过key直接拿出来sql的信息.所以Mybatis+spring为什么要xml文件中的id要和mapper接口中的方法名要一致,xml配置的包路径也要关联到mapper层的接口包路径.

第二步:二、mapperMethod.execute(sqlSession, args);

​ 作用就是去根据sql类型(select,delete,insert,update),然后去执行sql.在这里插入图片描述
图一百一十三:在这里插入图片描述
图一百一十四

这里去new一个MapperMethod,也就是去创建SqlCommand command和MethodSignature method.因为后面再执行sql语句的时候要用到这来个属性的sql数据.面向对象编程.在这里插入图片描述
图一百一十五:

这里去拿去mappedStatements集合中的信息了.具体在这个方法实现.在这里插入图片描述
图一百一十六:在这里插入图片描述
图一百一十七:在这里插入图片描述
图一百一十八:
在这里插入图片描述
开始返回到图:一百一十五执行new MethodSignature(config, mapperInterface, method)方法了.

图一百二十:在这里插入图片描述
图一百二十一:

获取当前方法的返回类型等等一些信息.在这里插入图片描述
到此开始返回到图:图一百一十二:执行第二步了.mapperMethod.execute(sqlSession, args);

图一百二十二:在这里插入图片描述
图一百二十三:在这里插入图片描述
图一百二十四:

执行sqlSession.selectList方法.command.getName()这里的command是之前在图一百一十五的时候new出来的.通过构造方法往这里面赋值的.这里拿取出来.在这里插入图片描述
图一百二十五:

执行SqlSessionTemplate代理类中的invoke方法了.在这里插入图片描述
图一百二十六:

这里为什么使用了SqlSessionTemplate类的invoke方法呢?就是代理对象调用了invoke方法呢?

因为之前在图九十二:调用setSqlSessionFacotry()方法的时候执行new SqlSessionTemplate(sqlSessionFactory);创建SqlSessionTemplate的时候.

第一步:
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
  }
第二步:
  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
    this(sqlSessionFactory, executorType,
        new MyBatisExceptionTranslator(
            sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
  }
第三步:
  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    notNull(executorType, "Property 'executorType' is required");

    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
     /**
     在这里通过newProxyInstance()方法,创建出sqlSessionProxy代理对象.放入SqlSessionInterce
     ptro实现了InvocationHandler接口的类.也就是下图中的内部类.
     */
    this.sqlSessionProxy = (SqlSession) newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class },
        new SqlSessionInterceptor());
  }

当前代理对象调用invoke方法的时候回直接进入DefaultSqlSession中的selectList()方法,也就是图一百二十七中的方法.相当于执行了Mybatis自己封装连接数据库执行sql语句的代码了.
在这里插入图片描述
图一百二十七:

这里的DefaultSqlSession类中的selectList()方法是Mybatis包下面的类.
在这里插入图片描述
图一百二十八:在这里插入图片描述
图一百二十九:在这里插入图片描述
图一百三十:在这里插入图片描述
图一百三十一:在这里插入图片描述
图一百三十二:在这里插入图片描述
图一百三十三:在这里插入图片描述
图一百三十四:在这里插入图片描述

  • 上面是查询list.下面是insert新增走的路径

图一百三十六:在这里插入图片描述
图一百三十七:在这里插入图片描述
图一百三十八:

经过SqlSessionTemplate的代理对象调用后去到DefaultSqlSession类中的insert方法.下图一百三十九.在这里插入图片描述
图一百三十九:

这里非常重要可以看到这里的insert方法调用的是update方法.其实delete方法也是调用的update方法.只是执行的sql语句不一样而已.

在这里插入图片描述
图一百四十:

可以看到这里是update方法中去执行新增的sql语句.在这里插入图片描述
图一百四十一:在这里插入图片描述
图一百四十二:在这里插入图片描述
图一百四十三:在这里插入图片描述
图一百四十四:在这里插入图片描述
图一百四十五:在这里插入图片描述
图一百四十六:

这里非常重要:

为什么一级缓存会很鸡肋

因为spring在这里把sqlSession的缓存给直接的关闭掉了,所以一级缓存没有什么做用.图一百四十七中有显示.

为什么要关闭呢?

因为这里的spring的并没有暴露给外部使用.不能先关闭就关闭.毕竟这是spring容器去超控的不需要程序员去执行.所以这里就直接关闭了.以免影响程序.在这里插入图片描述
图一百四十七:

直接关闭session.在这里插入图片描述
到这里为止就全部执行完毕了Mybaits+spring的执行流程了.**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值