reference
Depth analysis mybatis principle (c) how to integrate Spring
without his reference, I can not make this understanding.
@mapperScan registered MapperFactoryBean
![7547741-c4cbb884d0f544a9.jpg](https://upload-images.jianshu.io/upload_images/7547741-c4cbb884d0f544a9.jpg)
MapperFactoryBean those registered (a FactoryBean) in the spring will call its initialization getObject
method to generate specific Bean. (About FactoryBean, refer to Spring Source learning --FactoryBean implementation principle )
MapperFactoryBean initialization
![7547741-2231338b1fc40010.jpg](https://upload-images.jianshu.io/upload_images/7547741-2231338b1fc40010.jpg)
But after MapperFactoryBean instantiated, calling getObject
before, due MapperFactoryBean itself is a Bean, spring framework calls setSqlSessionFactory setSqlSessionTemplate and set its properties. So after getObject
use.
// SqlSessionDaoSupport.java
// MapperFactoryBean继承了SqlSessionDaoSupport
// 设置sqlSessionFactory, 顺便自动设置sqlSessionTemplate。所以如果没设定sqlSessionTemplate也没关系。
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
}
}
// 可以手动设置
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
After the getObject
middle:
-
getSqlSession
I use sqlSessionTemplate just set. -
getMapper(this.mapperInterface)
In -depth analysis of mybatis principle (b) have analyzed the
, the method will eventually return Mapper proxy class object.
// MapperFactoryBean.java
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
// SqlSessionDaoSupport.java
public SqlSession getSqlSession() {
return this.sqlSessionTemplate;
}
getObject call
You might ask, when will this MapperFactoryBean.getObject call it?
Remember when @mapperScan registered MapperFactoryBean ClassPathMapperScanner.processBeanDefinitions
way to do this:
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + beanClassName + "' mapperInterface");
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
definition.setBeanClass(this.mapperFactoryBeanClass);
// ...
}
}
}
There are two purposes:
- Sign up here for the Bean name beanClassName is
xx.xx.xxMapper
, but the actual Bean is MapperFactoryBean.
In the process of springboot initialization, we will call each BeangetBean
is instantiated, therefore MapperFactoryBean.getObject will be called. - When the Service is initialized, spring will deal @Autowire in Mapper, depending on the type of name
xx.xx.xxMapper
to find Bean, then callbeanFactory.getBean(beanName);
. However, according to the name found it is actually just registered MapperFactoryBean. Because it is FactoryBean, calling themgetBean
only triggergetObject
, thereby returning the proxy class object.
To verify the effect @Autowired on Mapper, debug their own, may refer to later.
Mapper debugging @autowired injection
- In
AutowiredAnnotationBeanPostProcessor.inject
theObject arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
debugging break point. - When the variable
beanName
when the name contains the Mapper or the Service Controller, enter the method.
Then follow into theresult = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
->instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
->beanFactory.getBean(beanName);
. Enter debugging. Familiar BeanFactory.getBean people should not have to debug know, the name of the corresponding Bean is MapperBeanFactory, is a BeanFactory, so in the end the methodbeanFactory.getBean(beanName);
returns a return value of getObject of MapperFactoryBean. This analysis is just getObject use it!
to sum up
- @MapperScan scan the specified package, each Mapper, with its registered name is the actual type of Bean defined MapperFactoryBean.
- Bean With these definitions, when the spring is instantiated Bean, these MapperFactoryBean is instantiated, initialized, the corresponding method is also provided
- In dealing with @autowired marked Mapper, it will return the result of calling MapperFactoryBean.getObject, which is
getSqlSession().getMapper(this.mapperInterface);
the. - Previous results will lead to
@Autowired SomeMapper mapper;
the injection of a class Mapper proxy, the proxy class will all database requests are handed over to the underlying operating SqlSession. - The previous step, Mapper handed over to the sqlSession actually a SqlSessionTemplate, SqlSessionTemplate in turn hand over any database operations to sqlSessionProxy, while the latter is based on the proxy class SqlSessionInterceptor created.
In other words, SqlSessionTemplate database operations will be intercepted SqlSessionInterceptor.invoke. - Call SqlSessionInterceptor.invoke the
getSqlSession
method is called internally when you needsession = sessionFactory.openSession(executorType);
to obtain a new session, it was in fact open a new connection.
That SqlSessionTemplate database operations will be intercepted SqlSessionInterceptor.invoke, must obtain before each operation to SqlSession (the actual type is DefaultSqlSession), this SqlSession:- Either reuse existing (such as multiplexing current transaction used)
-
Either new.
Therefore, a complete illustration of the above should read as follows:
mybatis mapper principle .jpg