原理說明
作用
根據@MapperScan注解配置的包路徑,掃描所有mapper介面,創建BeanDefinition物件,修改beanClass屬性值為MapperFactoryBean,注冊到Spring容器中,為后續Bean初始化做準備,
流程
- @MapperScan注解通過@Import方法匯入MapperScannerRegistrar類,MapperScannerRegistrar實作了ImportBeanDefinitionRegistrar介面,覆寫了registerBeanDefinitions方法,作用為手動注冊某個Bean的BeanDefinition到容器中【DefaultListableBeanFactory=>beanDefinitionMap】,
- ImportBeanDefinitionRegistrar介面是Spring的擴展點之一,Spring容器啟動時會回呼所有實作了ImportBeanDefinitionRegistrar介面的實作類中的registerBeanDefinitions方法,完成自定義BeanDefinition注冊,
- MapperScannerRegistrar的registerBeanDefinitions方法手動將MapperScannerConfigurer類通過這種方式將自己的BeanDefinition實體注冊到了容器中,為下一步Bean初始化做準備,
- MapperScannerConfigurer類實作了BeanDefinitionRegistryPostProcessor介面,該介面也是Spring的擴展點之一,Spring容器啟動時會回呼所有實作了BeanDefinitionRegistryPostProcessor介面的實作類中的postProcessBeanDefinitionRegistry方法,進行BeanDefinition注冊的后置處理,可以修改BeanDefinition物件,
- 在MapperScannerConfigurer的postProcessBeanDefinitionRegistry方法中創建了ClassPathMapperScanner物件,該物件對@MapperScan注解中配置的包路徑進行了掃描,為每個mapper介面創建對應的BeanDefinition實體,并修改所有實體中的beanClass屬性值為MapperFactoryBean,autoWireMode為byType,
- 將所有mapper介面的BeanDefinition實體注冊到Spring的容器中,為下一步實體化mapper介面做準備,
- MapperFactoryBean是一個很關鍵的類,MapperFactryBean集成了SqlSessionDaoSupport類,實作了FactoryBean介面,覆寫了getObject()方法,
- FactoryBean型別的Bean,在進行Bean初始化時,會通過呼叫自己的getObject()方法,獲取物件;而MapperFactoryBean覆寫后的getObject()方法,實際執行的是getSqlSession().getMapper(this.mapperInterface),通過此方法銜接到Mybaits,以JDK動態代理的方式,創建了一個代理物件,最后將代理物件注冊到了Spring容器中,
時序圖


Spring擴展點ImportBeanDefinitionRegistrar
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
// 通過@Import的方式注冊Bean定義
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
Spring擴展點BeanDefinitionRegistryPostProcessor
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean definition registry after its
* standard initialization. All regular bean definitions will have been loaded,
* but no beans will have been instantiated yet. This allows for adding further
* bean definitions before the next post-processing phase kicks in.
* @param registry the bean definition registry used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
// Bean定義注冊完畢之后,進行后置處理
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
注解@MapperScacn定義
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends Annotation> annotationClass() default Annotation.class;
Class<?> markerInterface() default Class.class;
String sqlSessionTemplateRef() default "";
String sqlSessionFactoryRef() default "";
Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;
String lazyInitialization() default "";
}
- 通過@Import注解,匯入了MapperScannerRegistrar類
- value、basePackages作用一致,用于宣告待掃描的mapper層包路徑,支持多組,
- basePackageClasses用于指定掃描某個類所在包下的所有組件,(@SpringBootApplication標識的啟動類)
- factoryBean:指定FactoryBean實作類,用于生成介面代理類,默認為MapperFactoryBean.class, 支持自定義,
MapperScannerRegistrar相關
該類實作了ImportBeanDefinitionRegistrar介面,在啟動時回呼registerBeanDefinitions方法注冊MapperScannerConfigurer.class的BeanDefinition到容器中,

關于ImportBeanDefinitionRegistrar:Spring擴展點之一,啟動時會回呼被覆寫的registerBeanDefinitions方法,注冊BeanDefinition到容器,
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
}
}
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
// 建造者模式創建MapperScannerConfigurer Bean定義物件
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
builder.addPropertyValue("processPropertyPlaceHolders", true);
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
builder.addPropertyValue("annotationClass", annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
builder.addPropertyValue("markerInterface", markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
}
String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
if (StringUtils.hasText(sqlSessionTemplateRef)) {
builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
}
String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
if (StringUtils.hasText(sqlSessionFactoryRef)) {
builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
}
List<String> basePackages = new ArrayList<>();
basePackages.addAll(
Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
.collect(Collectors.toList()));
basePackages.addAll(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());
}
MapperScannerConfigurer相關
該類實作了BeanDefinitionRegistryPostProcessor介面,BeanDefinitionRegistryPostProcessor也是Spring的擴展點之一,啟動時回呼被覆寫的postProcessBeanDefinitionRegistry方法,在回呼方法中創建了ClassPathMapperScanner物件,并呼叫doScan(basePackages)方法對@MapperScacn中的包路徑進行掃描創建、并修改BeanDefinition,

ClassPathMapperScanner相關
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
+ "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
掃描mapper層所有介面的Bean定義,設定beanClass和autoWireMode,
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
// 1.設定beanClass為MapperFactoryBean
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() + "'.");
// 2.設定autoWireMode=byType
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
definition.setLazyInit(lazyInitialization);
}
}
-
設定beanClass為MapperFactryBean
-
設定autoWireMode=byType
- No:即不啟用自動裝配,Autowire默認的值,
2. byName:通過屬性的名字的方式查找JavaBean依賴的物件并為其注入,比如說類Computer有個屬性printer,指定其autowire屬性為byName后,Spring IoC容器會在組態檔中查找id/name屬性為printer的bean,然后使用Seter方法為其注入,
3. byType:通過屬性的型別查找JavaBean依賴的物件并為其注入,比如類Computer有個屬性printer,型別為Printer,那么,指定其autowire屬性為byType后,Spring IoC容器會查找Class屬性為Printer的bean,使用set方法為其注入,
4. constructor:通byType一樣,也是通過型別查找依賴物件,與byType的區別在于它不是使用set方法注入,而是使用構造子注入,
- No:即不啟用自動裝配,Autowire默認的值,
public static final int AUTOWIRE_NO = 0;
public static final int AUTOWIRE_BY_NAME = 1;
public static final int AUTOWIRE_BY_TYPE = 2;
public static final int AUTOWIRE_CONSTRUCTOR = 3;
MapperFactoryBean相關

- 實作了FactoryBean介面,覆寫了getObject( )方法,容器初始化時通過getObject()回傳實際物件,
- 繼承了SqlSessionDaoSupport類,有成員變數sqlSessionTemplate,通過autoWire=byType屬性呼叫setSqlSessionFactory(sqlSessionFactory)初始化時,給sqlSessionTemplate賦值,
- getObject()方法通過Configuration物件獲以JDK動態代理的方式獲取代理類的實體,
- Configuration物件的mapperRegistry變數在Mybatis配置決議時賦值,mapperRegistry內部的knownMappers存盤所有mapper介面的map資訊,key為mapper介面的Class物件,value為持有對應Class物件的MapperProxyFactory實體,
- MapperProxyFactory是代理類工廠,用于生成代理物件MapperProxy的代理類,即為mapper介面的實際代理物件,
// MapperFactoryBean.java
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
// SqlSessionDaoSupport.java
public SqlSession getSqlSession() {
return this.sqlSessionTemplate;
}
// SqlSessionTemplate.java
@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}
// Configuration.java
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
// MapperRegistry.java
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);
}
}
}
// MapperProxyFactory.java
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
// MapperProxyFactory.java
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295991.html
標籤:Java
上一篇:SpringBoot + Kafka + ELK 完成海量日志收集(超詳細)
下一篇:Zookeeper應用場景
