springboot(二)——springboot自動配置解析

前言

用過springboot的確定很熟悉,它其中有個重要的特性,就是自動配置(平時習慣的一些設置的配置做爲默認配置)。springboot提倡無XML配置文件的理念,使用springboot生成的應用徹底不會生成任何配置代碼與XML配置文件。下面先看一個springboot集成mybatis的例子。
第一步: 引入pom文件java

<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文件加入以下配置:mysql

#指定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%2B8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

第三步: 加入實體類、dao、mapper文件
圖片描述
第四步:啓動類上面加入註解spring

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

第五步:至此,配置完成,只須要寫個單側,springboot已經完美集成mybatissql

@RunWith(SpringRunner.class)
@SpringBootTest
public 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結構以下:springboot

@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包,從而標識哪些自動配置的類mybatis

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

@Conditional

@Conditional 的做用,能夠根據條件去加載特定的bean,原理這邊不作探討,springboot基於此實現了幾個註解,比較方便的實現條件加載類
@ConditionalOnBean:Spring容器中是否存在對應的實例
@ConditionalOnMissingBean:Spring容器中是否缺乏對應的實例
經過查看MybatisAutoConfiguration中的SqlSessionFactory的寫法app

@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入口在哪裏以及如何實現的自動配置,這裏只是簡單的作了介紹,其中的一些源碼和細節就沒有分析了,我相信,入口知道了,接下來就好摳細節了。ide

本人也開通了微信公衆號:stonezplxjj和我的博客:http://www.zplxjj.com,更多文章歡迎關注公衆號:

圖片描述

相關文章
相關標籤/搜索