mybatis - @MapperScan

一. 测试代码

 

 

//实体类
public class User   {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    private SexEnum sex;
    //getter / setter
}

public enum SexEnum {

    Male("Male", "男"),

    Female("Female", "女");

    private String code;

    private String desc;    

    SexEnum(String code, String desc){
        this.code = code;
        this.desc = desc;
    }   
}

//Repository
@Repository
public interface UserMapper  {

    public User getById(Integer id);

    public List<User> getByAge(Integer age);

    public int insert(User user);
}

@SpringBootApplication
@MapperScan("com.study.demo.mybatis.mapper")
public class MybatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisApplication.class, args);
    }    
}

@Test
public void getById(){
    System.out.println("getById 开始执行...");
    User user = userMapper.getById(1);
    System.out.println(user);
    System.out.println("getById 结束执行...");
}

mapper.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.demo.mybatis.mapper.UserMapper">
    <insert id="insert">
        insert into user (name,age,email,sex) values(#{name}, #{age}, #{email}, #{sex})
    </insert>

    <select id="getById" resultType="com.study.demo.mybatis.vo.User">
        select * from user where id = #{id}
    </select>

    <select id="getByAge" resultType="com.study.demo.mybatis.vo.User">
        select * from user where age = #{age}
    </select>
</mapper>

配置文件:

spring:
    datasource:
        #type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/deco?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false
        username: root
        password: 123456

mybatis:
    mapper-locations: classpath:mapper/**Mapper.xml


@MapperScan("com.study.demo.mybatis.mapper")
主要做了两件事情:

1. 根据 "com.study.demo.mybatis.mapper" 配置进行mapper.java文件扫描.

  此处扫描到的就是 SchoolMapper.java 和 UserMapper.java 两个文件

2. 为扫描到的文件进行 BeanDefinition 注册

//关键代码: 
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 definition.setBeanClass(this.mapperFactoryBean.getClass()); ...... }

在进入此方法之前,  beanDefinitions 已经通过扫描得到, 

beanName beanClass
schoolMapper com.study.demo.mybatis.mapper.SchoolMapper
userMapper com.study.demo.mybatis.mapper.UserMapper

进入方法后, 会执行以下代码, 对 beanClass 进行重新赋值:

definition.setBeanClass(this.mapperFactoryBean.getClass());

这里的 mapperFactoryBean 是 ClassPathMapperScanner 的一个私有属性:

private MapperFactoryBean<?> mapperFactoryBean = new MapperFactoryBean<Object>();

也就是说, 后面对 beanName = userMapper 进行创建的时候, 会使用到  MapperFactoryBean

 

二. MapperFactoryBean

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {

  private Class<T> mapperInterface;

  private boolean addToConfig = true;

  public MapperFactoryBean() {
    //intentionally empty 
  }
  
  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;
  }
}

从代码上看, 实现了 FactoryBean 接口,  他是一个 工厂bean.

在创建 userMapper 的时候, 就会调用 MapperFactoryBean 的 getObject() 方法.

 md版本: https://files.cnblogs.com/files/elvinle/mybatis.zip

posted @ 2020-02-11 22:55  Sniper_ZL  阅读(7338)  评论(0编辑  收藏  举报