1:SpringBoot整合Mybatis这一块有点多,所以我打算分几部分来记录,整个流程大致是这样的,首先我们会配置一下我们编写sql的xml文件的位置,然后会编写dao层,最后在启动类上加上@MapperScan注解
2:Spring会解析我们配置的dao层接口,但是实例化出来的Bean都是代理类,然后会解析sql的xml配置文件,最后在执行dao层方法的时候通过动态代理会执行MapperProxy类的invoke()方法,最终返回数据库结果,所以今天先记录下SpringBoot是如何解析dao层接口,并将其生成代理类
3:创建一个SpringBoot项目,编写配置文件,整体结构图如下,还是很简单的
4:我们并没有在StudentMapper对象上加任何Spring的相关注解,那么Spring是如何将这个包下的对象都注册进容器的呢??那肯定是加了@MapperScan注解了,我们点进这个注解看下,发现有一个@Import注解,这个注解的作用是SpringBoot在初始化bean的时候也会处理这个注解中的bean,如果不清楚SpringBoot是如何初始化Bean的,可以看我主页的相关文章。
4:在ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//上面省略若干行
do {
//parse方法就是会处理@Import注解中的类,也会去注册Bean,具体的在另一篇文章解析过了
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
//重点关注这个方法
this.reader.loadBeanDefinitions(configClasses);
}
5:进入this.reader.loadBeanDefinitions(configClasses);这个方法
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
//进入这个方法之后,继续跟进这个方法
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
//重点关注这个方法,我们可以跟进这个方法,然后debug看下,其中的一个就是@MapperScan注解中的@Import注解中的那个类
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
6:执行方法
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
//会去执行MapperScanRegister类的registerBeanDefinitions方法
registrar.registerBeanDefinitions(metadata, this.registry));
}
7:进入MapperScanRegister.class的registerBeanDefinitions方法,其实看这个方法名字就可以知道这是往Spring容器中注册一个BeanDefinition了。整个方法就是为这个Bean注册一些属性,但是有几个属性要特别注意一下
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
//1:这个属性设置为了true,需要记住,后面会用到
builder.addPropertyValue("processPropertyPlaceHolders", true);
//中间的一些属性设置我忽略了
//下面这些属性就是设置我们dao层接口类的位置,可以看下图
List<String> basePackages = new ArrayList();
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
String lazyInitialization = annoAttrs.getString("lazyInitialization");
if (StringUtils.hasText(lazyInitialization)) {
builder.addPropertyValue("lazyInitialization", lazyInitialization);
}
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
8:在第7步我们设置好了我们mapper接口所在的包路径,然后就会去注册一个Bean了,重点来了!!!!,注册的这个Bean是什么??从图中可以看到是MapperScannerConfigure,记住不是MapperScannerResistar这个类,不要搞错了
9:MapperScannerConfigure.class类的结构,它实现了BeanDefinitionRegistryPostProcessor这个接口,这个接口的定义是:在注册bean之后会调用它的后置处理器也就是:void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;这个方法
10:进入MapperScannerConfigure.class类的postProcessBeanDefinitionRegistry方法
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
//这个属性在第7步说到过的要记住的,因为设置为了true,所以会进入if中的方法
if (this.processPropertyPlaceHolders) {
//你可以进入这个方法看下,其实就是给一些变量赋值,那么这些值是从哪来的呢??
//还是在第7步,我们当初注册的就是MapperScannerConfigure这个Bean,而且我们还
//给它设置了很多属性,这些属性就是从那里获取到的
this.processPropertyPlaceHolders();
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
if (StringUtils.hasText(this.lazyInitialization)) {
scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
}
scanner.registerFilters();
//核心方法:进入这个方法
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
}
//进入到这个方法之后,还是关注核心方法
publicublic int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//但是这个方法有二种实现了,一种是Spring的实现,一种是MyBatis的实现,所以我们要进入到
//MyBatis包下的ClassPathMapperScanner类的doScan()方法
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
11:进入到ClassPathMapperScanner类的doScan()方法
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
//这个方法就是获取我们mapper接口对象的beanDefinition,可以看下图,因为暂时只有一个接口,所以Set集合中只有一个元素
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> {
return "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.";
});
} else {
//获取到所有的BeanDefinition之后会做进一步的处理
this.processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
12:进入this.processBeanDefinitions(beanDefinitions);方法,其实这个方法就是MyBatis会mapper层接口生成代理类的关键了,可以看到处理之后我们的BeanDefinition编号才能了MapperFactoryBean。这个到底有什么用呢??我们只需要记住一点,等真正实例化Bean的时候,也就是在AbstractBeanFactory的doGetBean方法中,只要是实例化mapper下的接口返回的都是MapperFactoryBean,因为Spring在实例化bean都是先获取Bean对用的BeanDefinition之后,根据BeanDefinition进行实例化Bean。扯远了哈,,,,,所以你只需要记住这个方法的作用就是改造你的mapper接口下的Bean。然后注册进Spring容器中
13:到这里Mapper接口的Bean就已经注册好了,这也是为什么我们明明没有在mapper接口上加任何有关Spring的注解,但是Spring还是会将这些Bean注册进容器的原因。但是虽然Bean是注册了,但是还没有结束,因为我们的代理类还没有生成好。
14:生成代理类是在实例化Bean的时候,也就是在AbstractBeanFactory的doGetBean()方法中,这是实例化Bean的方法,可以看到我们其实是想实例化StudentMapper这个Bean的,但是实例化之后确实MapperFactoryBean这个对象,至于为什么可以看第12步
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
//生成代理类的核心方法
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
15:进入bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//最终会进入到这个方法,因为MapperFactoryBean是实现了factoryBean这个接口的
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//最终会执行这个方法,因为studentMapper是MapperFactoryBean,所以进入到MapperFactoryBean中的getObject()方法
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
16 进入MapperFactoryBean的getObject()方法中
public T getObject() throws Exception {
return this.getSqlSession().getMapper(this.mapperInterface);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
//最终通过代理工厂返回一个代理类
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}