欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring整合mybatis的底層原理分析

 更新時(shí)間:2025年05月21日 09:46:45   作者:神雕大俠mu  
這篇文章主要介紹了spring整合mybatis的底層原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

spring整合mybatis的底層原理

原理:

  • FactoryBean的自定義對(duì)象
  • jdk動(dòng)態(tài)代理Mapper接口對(duì)象

一、手寫一個(gè)spring集成mybatis

目錄結(jié)構(gòu):

1.1 入口類

public class Test {
    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AppConfig.class);
        context.refresh();

        UserService userService = (UserService)context.getBean("userService");
        userService.test();
    }
}

1.2 配置類

@CondorHeroMapperScan("com.athome.tulin.springmybatis.mapper")
@ComponentScan("com.athome.tulin.springmybatis")
public class AppConfig {
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException {
        System.out.println("4.依賴注入MemberMapper需要先創(chuàng)建對(duì)象………AppConfig…………SqlSessionFactory………");
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }
}

1.3 業(yè)務(wù)類

@Component
public class UserService {

    public UserService() {
        System.out.println("3.…………創(chuàng)建UserService…………");
    }

    //如何把mybatis生成的UserMapper的代理對(duì)象賦值給UserMapper
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private MemberMapper memberMapper;

    public void test(){
        System.out.println("7.……UserService…test…");
        System.out.println(userMapper.selectById());
        System.out.println(orderMapper.selectById());
        System.out.println(memberMapper.selectById());
    }
}

1.4 創(chuàng)建3個(gè)Mapper接口

public interface MemberMapper {

    @Select("select 'member' ")
    String selectById();
}
public interface OrderMapper {
    @Select("select 'order' ")
    String selectById();
}
public interface UserMapper {
    @Select("select 'user' ")
    String selectById();
}

1.5 自定義注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(CondorHeroImportBeanDefinitionRegistrar.class)
public @interface CondorHeroMapperScan {
    String value();
}

1.6 自定義fanctoryBean

public class CondorHeroFactoryBean implements FactoryBean {
    
    private Class mapperInterface;

    private SqlSession sqlSession;
    public CondorHeroFactoryBean(Class mapperInterface) {
        this.mapperInterface = mapperInterface;
    }
    /**
     * 從容器查找SqlSessionFactory 并獲取sqlSession 賦值于sqlSession
     * 掃描的時(shí)候有 beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
     * 那他就會(huì)自動(dòng)找set方法
     * @param sqlSessionFactory
     */
    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {
        System.out.println("5.……setSqlSession……");
        sqlSessionFactory.getConfiguration().addMapper(mapperInterface);
        this.sqlSession = sqlSessionFactory.openSession();
    }
    
    @Override
    public Object getObject() throws Exception {
        //動(dòng)態(tài)代理獲取UserMapper接口對(duì)象
        System.out.println("6.……getObject……");

       return sqlSession.getMapper(mapperInterface);
    }

    @Override
    public Class<?> getObjectType() {
        return mapperInterface;
    }
}

1.7 自定義Bean注冊(cè)類

public class CondorHeroImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        System.out.println("1.……registerBeanDefinitions……");
        //1.獲取注解上的指定路徑
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(CondorHeroMapperScan.class.getName());
        String path = (String)annotationAttributes.get("value");
        //2.掃描
        CondorHeroBeanDefinitionScanner scanner = new CondorHeroBeanDefinitionScanner(registry);
       scanner.addIncludeFilter(new TypeFilter() {
           @Override
           public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
               return true;
           }
       });

        scanner.scan(path);
    }
}

1.8 自定義掃描類

public class CondorHeroBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
    public CondorHeroBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition)  {
        //只關(guān)心接口(判斷是否是接口)
       return beanDefinition.getMetadata().isInterface();
    }

    /**
     * 掃描路徑并得到beanDefinition
     * @param basePackages
     * @return
     */
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        System.out.println("2.……doScan……");
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);

        for (BeanDefinitionHolder beanDefinitionHolder: beanDefinitionHolders) {
            GenericBeanDefinition beanDefinition = (GenericBeanDefinition)beanDefinitionHolder.getBeanDefinition();
            //設(shè)置值
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
            //設(shè)置名稱
            beanDefinition.setBeanClassName(CondorHeroFactoryBean.class.getName());

            //將MapperFactoryBean的注入模型設(shè)置為By-Type。也就是說,MapperFactoryBean中的setXxx中的屬性會(huì)從容器中來進(jìn)行查找
            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        }
        return beanDefinitionHolders;
    }
}

運(yùn)行結(jié)果是:
1.……registerBeanDefinitions……
2.……doScan……
3.…………創(chuàng)建UserService…………
4.依賴注入MemberMapper需要先創(chuàng)建對(duì)象………AppConfig…………SqlSessionFactory………
5.……setSqlSession……
6.……getObject……
5.……setSqlSession……
6.……getObject……
5.……setSqlSession……
6.……getObject……
7.……UserService…test… user order member

二、原理解析

2.1 通過@MapperScan導(dǎo)入了MapperScannerRegistrar類

2.2 MapperScannerRegistrar類實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口,所以Spring在啟動(dòng)時(shí)會(huì)調(diào)用MapperScannerRegistrar類中的registerBeanDefinitions方法

2.3 在registerBeanDefinitions方法中注冊(cè)一個(gè)MapperScannerConfigurer類型的BeanDefinition

2.4 而MapperScannerConfigurer實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口,所以Spring在啟動(dòng)過程中時(shí)會(huì)調(diào)用它的postProcessBeanDefinitionRegistry()方法

2.5 在postProcessBeanDefinitionRegistry方法中會(huì)生成一個(gè)ClassPathMapperScanner對(duì)象,然后進(jìn)行掃描(scanner.scan)2.6 通過利用Spring的掃描后,會(huì)把接口掃描出來并且得到對(duì)應(yīng)的BeanDefinition

2.7 接下來把掃描得到的BeanDefinition進(jìn)行修改,把BeanClass修改為MapperFactoryBean,把AutowireMode修改為byType(在類ClassPathMapperScanner的方法processBeanDefinitions中)

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    GenericBeanDefinition definition;
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();
      String beanClassName = definition.getBeanClassName();
      LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
          + "' mapperInterface");

      // the mapper interface is the original class of the bean
      // but, the actual class of the bean is MapperFactoryBean
      //設(shè)置值
      definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
      //設(shè)置名稱
      definition.setBeanClass(this.mapperFactoryBeanClass);

      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) {
        LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
        //將MapperFactoryBean的注入模型設(shè)置為By-Type。也就是說,MapperFactoryBean中的setXxx中的屬性會(huì)從容器中來進(jìn)行查找
       definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }
      definition.setLazyInit(lazyInitialization);
    }
  }

2.8 掃描完成后,Spring就會(huì)基于BeanDefinition去創(chuàng)建Bean了,相當(dāng)于每個(gè)Mapper對(duì)應(yīng)一個(gè)FactoryBean

2.9 在MapperFactoryBean中的getObject方法中,調(diào)用了getSqlSession()去得到一個(gè)sqlSession對(duì)象,然后根據(jù)對(duì)應(yīng)的Mapper接口生成一個(gè)Mapper接口代理對(duì)象,這個(gè)代理對(duì)象就成為Spring容器中的Bean

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {}
 @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }
  @Override
  public Class<T> getObjectType() {
    return this.mapperInterface;
  }

注意:這里的getObject調(diào)用時(shí)機(jī)是,在創(chuàng)建的對(duì)象依賴了Mapper對(duì)象就會(huì)去創(chuàng)建該Mapper對(duì)象,此時(shí)通過MapperFactoryBean去獲取

2.10 sqlSession對(duì)象是Mybatis中的,一個(gè)sqlSession對(duì)象需要SqlSessionFactory來產(chǎn)生

上面的getSqlSession()對(duì)應(yīng)源碼是:

2.11 MapperFactoryBean的AutowireMode為byType,所以Spring會(huì)自動(dòng)調(diào)用set方法,有兩個(gè)set方法,一個(gè)setSqlSessionFactory,一個(gè)setSqlSessionTemplate,而這兩個(gè)方法執(zhí)行的前提是根據(jù)方法參數(shù)類型能找到對(duì)應(yīng)的bean,所以Spring容器中要存在SqlSessionFactory類型的bean或者SqlSessionTemplate類型的bean

2.12 如果你定義的是一個(gè)SqlSessionFactory類型的bean,那么最終也會(huì)被包裝為一個(gè)SqlSessionTemplate對(duì)象,并且賦值給sqlSession屬性

這一步是程序員自己定義一個(gè)SqlSessionFactory,例如:

@CondorHeroMapperScan("com.athome.tulin.springmybatis.mapper")
@ComponentScan("com.athome.tulin.springmybatis")
public class AppConfig {
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException {
        System.out.println("4.依賴注入MemberMapper需要先創(chuàng)建對(duì)象………AppConfig…………SqlSessionFactory………");
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }
}

這里定義的SqlSessionFactory 會(huì)賦值于2.10的sqlSessionTemplate

2.13 而在SqlSessionTemplate類中就存在一個(gè)getMapper方法,這個(gè)方法中就產(chǎn)生一個(gè)Mapper接口代理對(duì)象

2.14 當(dāng)執(zhí)行該代理對(duì)象的某個(gè)方法時(shí),就會(huì)進(jìn)入到Mybatis框架的底層執(zhí)行流程

至此:業(yè)務(wù)類中的引入Mapper對(duì)象就復(fù)制成功。

 @Autowired
    private OrderMapper orderMapper;

即:這時(shí)候的orderMapper就 是賦值了代理對(duì)象的對(duì)象是有值 的。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論