一.测试方法
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);
}