spring整合mybatis原理

文章详细介绍了如何在Spring中使用@Test进行MyBatis的测试,包括配置类UserConfig的设置,SqlSessionFactoryBean的作用,以及MapperScannerConfigurer如何扫描Mapper接口并注册到Spring。同时阐述了在getBean过程中,如何通过FactoryBean生成Mapper接口的代理类。
摘要由CSDN通过智能技术生成

一.测试方法

1.主测试方法:

	@Test
	public void userConfigTest(){
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
		UserMapper mapper = context.getBean(UserMapper.class);
		User user = mapper.findUserById(16);
		System.out.println(user);
	}

2.配置类

@Configuration
@ComponentScan("com.mingdong.annotation.mybatis")
public class UserConfig {

	@Bean
	public BasicDataSource dataSource(){

		BasicDataSource basicDataSource = new BasicDataSource();

		basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
		basicDataSource.setUrl("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8");
		basicDataSource.setUsername("root");
		basicDataSource.setPassword("123456");
		basicDataSource.setMaxActive(10);
		basicDataSource.setMaxIdle(5);

		return basicDataSource;
	}

	@Bean
	public SqlSessionFactoryBean sqlSessionFactoryBean(){
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource());
		return sqlSessionFactoryBean;
	}

	@Bean
	public MapperScannerConfigurer mapperScannerConfigurer(){
		MapperScannerConfigurer mapperScannerConfigurer  = new MapperScannerConfigurer();
		mapperScannerConfigurer.setBasePackage("com.mingdong.annotation.mybatis");
		return mapperScannerConfigurer;
	}

}

3.Mapper接口

public interface UserMapper {

	@Select("SELECT * from user where id = #{v}")
	public User findUserById(int id);

}

二、SqlSessionFactoryBean为FactoryBean,在getBean方法时会调用getObject方法,返回mybatis的sqlSessionFactory工厂;

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
  @Override
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }
}

三、MapperScannerConfigurer扫描包类,这个实现了BeanDefinitionRegistryPostProcessor,spring初始化时,会调用postProcessBeanDefinitionRegistry方法,这个方法创建了ClassPathMapperScanner,主要在scan方法进行扫描逻辑

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
    @Override
  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();
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }
}

四、doScan方法中获取包下的所有接口,并封装为BeanDefinitionHolder,调用registerBeanDefinition把BeanDefinition注册到spring中,到这里扫描完成

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			//1.找出扫描包下所有以.class的文件,封装到Resource中(有盘符的全路径),2.筛选出有@component注解的类 3,返回beanDifinition
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

五、因为上面扫描注册了接口BeanDefinition,在spring的初始化调用getBean方法生成代理类,这个接口BeanDefinition对应的类型为MapperFactoryBean,MapperFactoryBean为FactoryBean,下面为其getObject方法,调用mybatis的getMapper生成代理类

  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值