前言

用过springboot的肯定很熟悉,它其中有个重要的特性,就是自动配置(平时习惯的一些设置的配置作为默认配置)。springboot提倡无XML配置文件的理念,使用springboot生成的应用完全不会生成任何配置代码与XML配置文件。下面先看一个springboot集成mybatis的例子。
第一步: 引入pom文件

        <dependency>            <groupId>org.mybatis.spring.boot</groupId>            <artifactId>mybatis-spring-boot-starter</artifactId>            <version>2.0.1</version>        </dependency>        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>5.1.47</version>        </dependency>

第二步: 因为我使用的xml配置文件去使用mybatis,在application.properties文件加入如下配置:

#指定mapper文件位置mybatis.mapper-locations=classpath:mapper/*.xml#数据源信息spring.datasource.url=jdbc:mysql://127.0.0.1:3306/zplxjj?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8spring.datasource.username=rootspring.datasource.password=123456spring.datasource.driver-class-name=com.mysql.jdbc.Driver

第三步: 加入实体类、dao、mapper文件

第四步:启动类上面加入注解

@SpringBootApplication@MapperScan("com.stone.zplxjj.dao")public class Application {    public static void main(String[] args) {        SpringApplication.run(Application.class, args);    }}

第五步:至此,配置完成,只需要写个单侧,springboot已经完美集成mybatis

@RunWith(SpringRunner.class)@SpringBootTestpublic class ApplicationTests {    @Autowired    UserMapper userMapper;    @Test    public void testMybatis() {        System.out.println(userMapper.selectByPrimaryKey(1L));    }}

@EnableAutoConfiguration

通过上面的例子,我们发现集成mybatis特别简单,那些繁琐的类的注入都没有写,只需要加入数据库的一些配置即可,那这其中@EnableAutoConfiguration功不可没。@EnableAutoConfiguration 注解已经在@SpringBootApplication里面了

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(    excludeFilters = {@Filter(    type = FilterType.CUSTOM,    classes = {TypeExcludeFilter.class}), @Filter(    type = FilterType.CUSTOM,    classes = {AutoConfigurationExcludeFilter.class})})public @interface SpringBootApplication {    @AliasFor(        annotation = EnableAutoConfiguration.class    )    Class<?>[] exclude() default {};    @AliasFor(        annotation = EnableAutoConfiguration.class    )    String[] excludeName() default {};    @AliasFor(        annotation = ComponentScan.class,        attribute = "basePackages"    )    String[] scanBasePackages() default {};    @AliasFor(        annotation = ComponentScan.class,        attribute = "basePackageClasses"    )    Class<?>[] scanBasePackageClasses() default {};}

我们看到@EnableAutoConfiguration结构如下:

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import({AutoConfigurationImportSelector.class})public @interface EnableAutoConfiguration {    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";    Class<?>[] exclude() default {};    String[] excludeName() default {};}

这其中起作用的一个重要注解@Import,这个Spring提供的一个注解,可以导入配置类或者Bean到当前类中,我们进入到AutoConfigurationImportSelector类中查看,方法太长,截取核心的两个方法:

    public String[] selectImports(AnnotationMetadata annotationMetadata) {        if (!this.isEnabled(annotationMetadata)) {            return NO_IMPORTS;        } else {            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());        }    }    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {        if (!this.isEnabled(annotationMetadata)) {            return EMPTY_ENTRY;        } else {            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);            configurations = this.removeDuplicates(configurations);            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);            this.checkExcludedClasses(configurations, exclusions);            configurations.removeAll(exclusions);            configurations = this.filter(configurations, autoConfigurationMetadata);            this.fireAutoConfigurationImportEvents(configurations, exclusions);            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);        }    }

通过项目启动后,打上注解,可以看到MybatisAutoConfiguration引入了进来

而MybatisAutoConfiguration能引入进来,其实是在mybatis-spring-boot-autoconfigure-2.0.1.jar包里面的spring.factories指定的,通过调用SpringFactoriesLoader.loadFactoryNames()来扫描加载含有META-INF/spring.factories文件的jar包,从而标识哪些自动配置的类

# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

@Conditional

@Conditional 的作用,可以根据条件去加载特定的bean,原理这边不做探讨,springboot基于此实现了几个注解,比较方便的实现条件加载类
@ConditionalOnBean:Spring容器中是否存在对应的实例
@ConditionalOnMissingBean:Spring容器中是否缺少对应的实例
通过查看MybatisAutoConfiguration中的SqlSessionFactory的写法

    @Bean    @ConditionalOnMissingBean    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();        factory.setDataSource(dataSource);        factory.setVfs(SpringBootVFS.class);        if (StringUtils.hasText(this.properties.getConfigLocation())) {            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));        }        this.applyConfiguration(factory);        if (this.properties.getConfigurationProperties() != null) {            factory.setConfigurationProperties(this.properties.getConfigurationProperties());        }        if (!ObjectUtils.isEmpty(this.interceptors)) {            factory.setPlugins(this.interceptors);        }        if (this.databaseIdProvider != null) {            factory.setDatabaseIdProvider(this.databaseIdProvider);        }        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());        }        if (this.properties.getTypeAliasesSuperType() != null) {            factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());        }        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());        }        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {            factory.setMapperLocations(this.properties.resolveMapperLocations());        }        return factory.getObject();    }

结语

通过上面分析mybatis如何集成springboot,知道了springboot入口在哪里以及如何实现的自动配置,这里只是简单的做了介绍,其中的一些源码和细节就没有分析了,我相信,入口知道了,接下来就好抠细节了。

本人也开通了微信公众号:stonezplxjj,更多文章欢迎关注公众号: