MapperScannerConfigurer在mybatis-spring的妙用

来源:互联网 发布:js input value 赋值 编辑:程序博客网 时间:2024/06/06 00:02

概述

在mybatis中我们经常这样定义OrderInfoMapper这样的接口,然后配置OrderInfoMapper.xml映射到OrderInfoMapper,就可以直接注入OrderInfoMapper

public interface OrderInfoMapper {    int insert(Order order);}

定义一个SQL操作

<insert id="insert" parameterType="com.test.order.bo.Order">INSERT IGNORE INTO orderdetail...</insert>

就可以直接注入使用

    @Autowired    private OrderInfoMapper orderInfoMapper;     @Override    public int insertExample(Order order) {        int effectNum = orderInfoMapper.insert(order);        return effectNum;    }

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>

那么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;}

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));  }...}

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;  }

最后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;  }
1 0
原创粉丝点击