<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<!-- 定义别名 -->
<property name="typeAliasesPackage" value="com.booway.pojo"></property> <!-- 配置映射文件的位置,如果配置文件与mapper接口在同一个位置,可以不写 -->
<!-- <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property> -->
<!-- <property name="mapperLocations">
<array>
<value>classpath:mybatis/mapper/User.xml</value>
</array>
</property> --> </bean> <!-- 将mybatis实现的接口注入到spring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
<property name="basePackage" value="com.booway.mapper"></property>
</bean> 看下这个类的实现MapperScannerConfigurer 类申明为:
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware 这个类实现了BeanDefinitionRegistryPostProcessor,InitializingBean,ApplicationContextAware,BeanNameAware接口 实现了BeanDefinitionRegistryPostProcessor接口意味着在beanDefinition注册之后就会调用这个接口的postProcessBeanDefinitionRegistry方法。实现了InitializingBean接口意味在bean创建初始化时会调用afterPropertiesSet方法。ApplicationContextAware意味着会注入application实例,BeanNameAware意味着会注入这个bean当前的beanName 这几个接口使用的顺序为,BeanDefinitionRegistryPostProcessor,BeanNameAware,ApplicationContextAware,InitializingBean 1、先来看BeanDefinitionRegistryPostProcessor接口的实现方法 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.registerFilters();
//扫描指定包下的类,将com.test.a,com.test,b拆分为数组
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
} public void registerFilters() {
boolean acceptAllInterfaces = true;//默认获取所有的接口作为mybatis的mapper接口 // if specified, use the given annotation and / or marker interface
if (this.annotationClass != null) {
//如果指定了标记的注解类型,那么就使用这个注解来标记mybatis的mapper接口
addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
acceptAllInterfaces = false;
} // override AssignableTypeFilter to ignore matches on the actual marker interface
//通过标记的接口来识别是不是mapper接口,只要继承了指定接口的就是,不过此处的逻辑认为继承了这个接口的就返回false,也就是不是mybatis的mapper接口
if (this.markerInterface != null) {
addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
@Override
protected boolean matchClassName(String className) {
return false;
}
});
acceptAllInterfaces = false;
}
//如果acceptAllInterfaces为true,也就是没有指定任何筛选逻辑,那么认为任何接口都返回true
if (acceptAllInterfaces) {
// default include filter that accepts all classes
addIncludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});
}
//排除package-info.java
// exclude package-info.java
addExcludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
}
});
} public int scan(String... basePackages) {
//获取已经注册bean的个数
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//扫描
doScan(basePackages); // Register annotation config processors, if necessary.如果包含注解配置,那么就注册注解配置处理器。
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//新增加的beandefinitoinCount就是mybatis扫描添加的。
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 {
//处理获取到的beanDefinition
processBeanDefinitions(beanDefinitions);
} return beanDefinitions;
} 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) {
//获取范围元数据,通过类获取这个类的scope范围还有代理模式
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//将解析出来的scope设置到beanDefinition中
candidate.setScope(scopeMetadata.getScopeName());
//使用命名生成器生成beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//给这个beanDefinition设置默认的属性,比如默认的lazy属性啊,等等
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
//设置注解配置的一些属性 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//检查候选beanDefinition类,以确定是否可以要进行注册,防止重复注册
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;
} public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
//classpath*:com/test/a/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + this.resourcePattern;
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);//通过spring的PathMatchingResourcePatternResolver,获取到所有符合条件的class资源
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {//如果是这个资源是可读的
try {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);//将类包装成元数据读取器,底层使用的ASM框架。
if (isCandidateComponent(metadataReader)) {//通过过滤器配置这个类是否是候选组件
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);//这个类继承自GenericBeanDefinition
sbd.setResource(resource);
sbd.setSource(resource);
//判断这个类是不是独立的,是不是具体的(即不是抽象或接口,可以被继承)
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
} protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//判断当前类是否是排除的,如果是被排除,那么就不是候选的mapper
接口
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
//判断当前类是否被包含
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return isConditionMatch(metadataReader);
}
}
return false;
} @Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
//获取Scope注解的value属性值
metadata.setScopeName(attributes.getAliasedString("value", this.scopeAnnotationType, definition.getSource()));
//获取proxyMode属性指定的代理模式
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
} 这样就将定义的类变成了beanDefinition注册到spring中 private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition(); if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
} // the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
//给这个 beanDefinition定义构造参数为自己,因为下面会定义FactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
//设置工厂bean
definition.setBeanClass(this.mapperFactoryBean.getClass());
//设置addToConfig属性
definition.getPropertyValues().add("addToConfig", this.addToConfig);
//使用指定的工厂
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {//如果指定了sqlSessionFactory,表示配置文件中已经配置了对应的beanName
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;
}
//如果没有指定明确的工厂bean使用,那么就设置转配模式为按类型进行装配,让spring自己到容器中找到对应bean进行装配。
if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
} 那么问题来了,既然最后把所有的类的都变为了MapperFactoryBean来创造,那么这个MapperFactoryBean是怎么构造这些接口的实现类的呢? MapperFactoryBean实现了FactoryBean接口 //MapperFactoryBean的类定义
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { private Class<T> mapperInterface; private boolean addToConfig = true; public MapperFactoryBean() {
//intentionally empty
}
//这个构造参数在上面的分析中已经看到,它把对应Mapper接口设置进来了
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
} /**
* {@inheritDoc}
*/
@Override
protected void checkDaoConfig() {
super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
} /**
* {@inheritDoc}
*/
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
} /**
* {@inheritDoc}
*/
@Override
public Class<T> getObjectType() {
return this.mapperInterface;
} /**
* {@inheritDoc}
*/
@Override
public boolean isSingleton() {
return true;
} //------------- mutators -------------- /**
* Sets the mapper interface of the MyBatis mapper
*
* @param mapperInterface class of the interface
*/
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
} /**
* Return the mapper interface of the MyBatis mapper
*
* @return class of the interface
*/
public Class<T> getMapperInterface() {
return mapperInterface;
} /**
* If addToConfig is false the mapper will not be added to MyBatis. This means
* it must have been included in mybatis-config.xml.
* <p/>
* If it is true, the mapper will be added to MyBatis in the case it is not already
* registered.
* <p/>
* By default addToCofig is true.
*
* @param addToConfig
*/
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
} /**
* Return the flag for addition into MyBatis config.
*
* @return true if the mapper will be added to MyBatis in the case it is not already
* registered.
*/
public boolean isAddToConfig() {
return addToConfig;
}
} //底层就是使用的mybatis获取接口实现的方法。
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}

最新文章

  1. python学习笔记-Day6(3)
  2. 对C#对象的Shallow、Deep Cloning认识【转】
  3. 跟我学 NHibernate (二)
  4. 解北大OJ1088滑雪问题的记录
  5. .Net平台开源作业调度框架Quartz.Net
  6. 关于activiti流程通过、驳回、会签、转办、中止、挂起等核心操作功能的封装
  7. MP3/WAV 播放
  8. linux之SQL语句简明教程
  9. Juniper srx防火墙NAT配置
  10. JavaScript面向对象旅程(下)
  11. 办理英属哥伦比亚大学(本科)学历认证『微信171922772』UBC学位证成绩单使馆认证University of British Columbia
  12. LeetCode-4. 两个排序数组的中位数(详解)
  13. (六十七)Xcode导入XMPPFramework框架
  14. 预计2019年发布的Vue3.0到底有什么不一样的地方?
  15. laravel部署创建新项目 助记
  16. shell脚本新建文件夹或用到目录时多出M或者?之类的
  17. SQL Server 一致性读
  18. CF809C Find a car
  19. Python入门:求1-2+3-4+5...99的所有数的和
  20. 常用sql自定义函数

热门文章

  1. PDF Expert for Mac v2.4.22 中文破解版下载 PDF阅读编辑软件
  2. 【maven 】jar包冲突-记一次冲突解决
  3. Git的忽略、分支、分支与主线的合并、远程仓库的操作
  4. selenium3+python3自动化测试学习之模拟事件处理
  5. Confluence5.6.6安装和破解
  6. Ubuntu18.04安装postgresql-10
  7. ajax请求中 两种csrftoken的发送方法
  8. Don’t Repeat Yourself
  9. kuangbin专题 专题一 简单搜索 迷宫问题 POJ - 3984
  10. 关于pcl索引的使用