上篇mybatis 映射文件加载是分析了一下咱们全部的xml映射文件如何加载的,但在我学习ssm的过程当中,发现dao层的接口在service层会注入一个实例化对象,直接能够使用,但咱们并无作dao层的实现类,html
很好奇的去查了查资料,下面就分析一下java
mybatis配置文件spring
mybatis是经过org.mybatis.spring.mapper.MapperScannerConfigurer类来实现dao层扫描的 咱们进入MapperScannerConfigurer这个类,有一个postProcessBeanDefinitionRegistry方法sql
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(); //扫描basepackage包下的全部dao接口 scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }
进入doscan方法mybatis
//由父类去找到符合条件的interface类,并转化为bean类 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 { //处理找到的interface bean类 processBeanDefinitions(beanDefinitions); } return beanDefinitions;
而后看processBeanDefinitions方法app
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 definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
//设置beanclass类型为mapperFactoryBean definition.setBeanClass(this.mapperFactoryBean.getClass()); 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) { if (logger.isDebugEnabled()) { logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); } definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } } }
最终会把dao层接口包装成MapperFactoryBean函数
也就是说咱们会把全部的dao层文件,封装成和如下配置文件同样的效果,是否是很熟悉了post
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.zsh.dao.UserMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
以上是咱们扫描dao层的原理,下面咱们继续分析如何自动实例化接口学习
再说自动实例化接口以前咱们了解一下什么是动态代理 Java 动态代理机制分析及扩展 this
上面是经过工厂方法建立Bean
首先咱们定位到类 org.mybatis.spring.mapper.MapperFactoryBean
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { private Class<T> mapperInterface; private boolean addToConfig;
能够看到该类实现了org.springframework.beans.factory.FactoryBean接口,经过调用
org.mybatis.spring.mapper.MapperFactoryBean.getObject()方法来得到Bean
public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); }
咱们经过分析以上的getSqlSession()能够看出getMapper的实现类是SqlSessionTemplate,咱们跳转到SqlSessionTemplate看一下getMapper方法
public <T> T getMapper(Class<T> type) { return getConfiguration().getMapper(type, this); }
能够看到,它首先调用了自身的getConfiguration()方法返回一个Configuration对象,而后再调用Configuration对象的getMapper方法
咱们直接定位到Configuration的getMapper方法
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
直接定位到mapperRegistry.getMapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
在这个方法里,首先得到一个MapperProxyFactory的对象mapperProxyFactory,而后调用该对象的newInstance方法建立咱们须要的bean,定位到newInstance方法
public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }
最后咱们进入newInstance这个重载函数
protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }
在这里用jdk的动态代理建立了一个代理对象,也就是说,咱们最终是对mapper的全部接口分别建立了各自的代理对象,经过代理对象来执行咱们的sql
参考并感谢
https://www.cnblogs.com/question-sky/p/6654101.html
http://blog.csdn.net/tanqidong1992/article/details/48026491
https://www.jianshu.com/p/3e619786dd18