概述
在mybatis中我们经常这样定义OrderInfoMapper这样的接口,然后配置OrderInfoMapper.xml映射到OrderInfoMapper,就可以直接注入OrderInfoMapper
public interface OrderInfoMapper { int insert(Order order); }12345
定义一个SQL操作
<insert id="insert" parameterType="com.test.order.bo.Order"> INSERT IGNORE INTO orderdetail...</insert>12345
就可以直接注入使用
@Autowired private OrderInfoMapper orderInfoMapper; @Override public int insertExample(Order order) { int effectNum = orderInfoMapper.insert(order); return effectNum; }12345678
XML配置扫描包路径,Spring会扫描指定包中的类与相应的mapper文件对应起来
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.test.soa.order.mapper"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean>1234
那么Spring到底是怎么建立数据库的连接然后执行SQL操作?这其实都要归功于MapperScannerConfigurer的功能。MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor。
BeanDefinitionRegistryPostProcessor的使用
BeanDefinitionRegistryPostProcessor接口有获取BeanDefinitionRegistry的能力,BeanDefinitionRegistry是Spring所有Bean的注册中心,通过这个注册中心可以自定义修改已经定义好的Bean,这样可以加工甚至替换已经定义的Bean,高度化定制Bean的创建。
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 */ void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException; }12345678910111213
MapperScannerConfigurer实现了postProcessBeanDefinitionRegistry方法,将已经注册好的Bean重新替换
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { 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(); scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); } ... }1234567891011121314151617181920212223
ClassPathMapperScanner的doScan方法,会将mapper包中的类替换成MapperFactoryBean,MapperFactoryBean实现了FactoryBean接口,每次生成对应Bean的时候,其实调用的FactoryBean的getObject方法。也就是说我们在注入OrderInfoMapper的时候,其实调用的是FactoryBean的getObject方法,而这个方法会生成OrderInfoMapper的代理类MapperProxy的实例。mybatis-spring就这样“偷梁换柱”的把mapper包中的类的实例替换成了代理类的实例
@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 { for (BeanDefinitionHolder holder : beanDefinitions) { GenericBeanDefinition 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.getPropertyValues().add("mapperInterface", definition.getBeanClassName()); definition.setBeanClass(MapperFactoryBean.class); 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); } } } return beanDefinitions; }1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
最后OrderInfoMapper.insert真正执行的方法是MapperMethod的execute
public class MapperMethod { ....public Object execute(SqlSession sqlSession, Object[] args) { Object result; if (SqlCommandType.INSERT == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); } else if (SqlCommandType.UPDATE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); } else if (SqlCommandType.DELETE == command.getType()) { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); } else if (SqlCommandType.SELECT == command.getType()) { if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { result = executeForMap(sqlSession, args); } else { Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); } } else { throw new BindingException("Unknown execution method for: " + command.getName()); } if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; }
网友评论
更多精彩分享
- 陆老师 [海军工程大学 硕士 — 嵌入式开发专家] 2024-03-26 11:26:03.003
- 时光飞逝 2024-03-26 11:25:53.823
- 纸上得来终觉浅 2024-03-26 11:25:42.68
- 软件行业发展七大方向 2024-03-26 11:25:34.457
- 如何组建测试团队? 2024-03-26 11:25:25.33
- 在青岛学习JavaEE哪家学校最好? 2024-03-26 11:25:16.78
- 教务排课系统 2024-03-26 11:24:56.74
- 青岛帕特智能科技有限公司 2024-03-26 11:24:30.433
- 消息队列NetMQ 原理分析4-Socket、Session、Option和Pipe 2024-03-26 11:24:15.657
- 感谢,我亲爱的万码学堂 2024-03-26 11:12:06.6