1革砸、概述
原生Mybatis源碼簡析(上)
原生Mybatis源碼簡析(下)
在介紹原生Mybatis源碼簡析文章中爆阶,我們知道泛粹,Mapper接口的生命周期是在方法級別,方法執(zhí)行結(jié)束器仗,Mapper接口的動態(tài)代理實(shí)現(xiàn)類的生命就終結(jié)了。在下一次執(zhí)行時童番,會再次重新生成新的代理類精钮。但是當(dāng)mybatis與spring結(jié)合使用時,mapper接口的代理實(shí)現(xiàn)類的生命周期是全局的剃斧,這是如何實(shí)現(xiàn)的呢轨香?首先在spring中引入mybatis時,是需要加入mybatis-spring包的引用的悯衬。在spring的xml配置中需要加入如下配置:
<!-- spring和MyBatis完美整合弹沽,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自動掃描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/javen/mapping/*.xml"></property>
</bean>
<!-- DAO接口所在包名檀夹,Spring會自動查找其下的類 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.javen.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
那mapper接口的代理實(shí)現(xiàn)類的單例實(shí)現(xiàn)機(jī)制,定是與這兩個bean有關(guān)了策橘。
2炸渡、SqlSessionFactoryBean
SqlSessionFactoryBean,從名字就可看出他是一個FactoryBean丽已,如此就直接看起getObject方法
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = buildSqlSessionFactory();
}
在getObject方法中調(diào)用了afterPropertiesSet方法蚌堵,內(nèi)部又調(diào)用了buildSqlSessionFactory方法,該方法內(nèi)容很長沛婴,不再貼代碼了吼畏,但方法實(shí)現(xiàn)比較簡單,就是根據(jù)SqlSessionFactoryBean的眾多配置屬性來構(gòu)建出Configuration對象嘁灯,進(jìn)而實(shí)例化SqlSessionFactory對象泻蚊。與原廠mybatis的實(shí)現(xiàn)大同小異。
3丑婿、MapperScannerConfigurer
MapperScannerConfigurer類實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口性雄,則重點(diǎn)看下postProcessBeanDefinitionRegistry方法的實(shí)現(xiàn)
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
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);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
ClassPathMapperScanner類是mybatis-spring框架提供的類,實(shí)現(xiàn)了spring框架的ClassPathBeanDefinitionScanner類羹奉。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
ClassPathBeanDefinitionScanner類的doScan方法會根據(jù)傳入的basePackage秒旋,掃描包下的所有.class文件,并根據(jù)該類文件生成相應(yīng)的BeanDefinition對象诀拭。針對mybatis的mapper接口迁筛,這里生成的BeanDefinition對象其實(shí)是半成品的對象,他的beanClass屬性是接口的全限定類名耕挨。然后將半成品的BeanDefinition對象集合返回细卧,在ClassPathMapperScanner類的processBeanDefinitions方法中,對這些半成品的BeanDefinition進(jìn)行二次加工俗孝。
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);
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
LOGGER.warn(() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
LOGGER.warn(() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
重點(diǎn)是definition.setBeanClass(this.mapperFactoryBeanClass);這段方法酒甸。
private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;
MapperFactoryBean類也是一個FactoryBean,重置了beanClass屬性之后赋铝,此時的BeanDefinition就是一個成品的了插勤,之后實(shí)例化的時候,mapper接口對應(yīng)的對象就是MapperFactoryBean的實(shí)例革骨。如此便實(shí)現(xiàn)了mapper接口的全局單例話农尖。
有空得再看看源碼分析下,spring的事務(wù)是如何與mybatis的事務(wù)整合在一起的良哲?