Spring Boot 啓動過程分析(一)

1. Spring Boot 入口——main方法

@SpringBootApplication
public class Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

從上面代碼可以看出,Annotation定義(@SpringBootApplication)和類定義(SpringApplication.run)最爲耀眼,所以分析 Spring Boot 啓動過程,我們就從這兩位開始。

2. 核心註解

2.1 @SpringBootApplication

@SpringBootApplication 是最常用也幾乎是必用的註解,源碼如下:

/**
 * Indicates a {@link Configuration configuration} class that declares one or more
 * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
 * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
 * annotation that is equivalent to declaring {@code @Configuration},
 * {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
 
 * 標示一個聲明有一個或多個的@Bean方法的Configuration類並且觸發自動配置(EnableAutoConfiguration)  
 * 和組建掃描(ComponentScan)。
 * 這是一個相當於@Configuration@EnableAutoConfiguration@ComponentScan 三合一的組合註解。
 */
@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, attribute = "exclude")
    Class<?>[] exclude() default {};

    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
    String[] excludeName() default {};

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

從源碼聲明可以看出,@SpringBootApplication相當於 @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan ,因此我們直接拆開來分析。

2.2 @SpringBootConfiguration

@SpringBootConfiguration 是繼承自Spring的 @Configuration 註解,@SpringBootConfiguration 作用相當於 @Configuration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

spring 3.0中增加了@Configuration,@Bean。可基於JavaConfig形式對 Spring 容器中的bean進行更直觀的配置。SpringBoot推薦使用基於JavaConfig的配置形式。

基於xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
       default-lazy-init="true">
    <bean id="mockService" class="..MockServiceImpl">
    ...
    </bean>
</beans>

基於JavaConfig配置:

@Configuration
public class MockConfiguration{
    @Bean
    public MockService mockService(){
        return new MockServiceImpl();
    }
}

總結,@Configuration相當於一個spring的xml文件,配合@Bean註解,可以在裏面配置需要Spring容器管理的bean。

2.3 @ComponentScan

@ComponentScan源碼:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    /**
     * 對應的包掃描路徑 可以是單個路徑,也可以是掃描的路徑數組
     * @return
     */
    @AliasFor("basePackages")
    String[] value() default {};
    /**
     * 和value一樣是對應的包掃描路徑 可以是單個路徑,也可以是掃描的路徑數組
     * @return
     */
    @AliasFor("value")
    String[] basePackages() default {};
    /**
     * 指定具體的掃描類
     * @return
     */
    Class<?>[] basePackageClasses() default {};
    /**
     * 對應的bean名稱的生成器 默認的是BeanNameGenerator
     * @return
     */
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    /**
     * 處理檢測到的bean的scope範圍
     */
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
    /**
     * 是否爲檢測到的組件生成代理
     */
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    /**
     * 控制符合組件檢測條件的類文件   默認是包掃描下的
     * @return
     */
    String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
    /**
     * 是否對帶有@Component @Repository @Service @Controller註解的類開啓檢測,默認是開啓的
     * @return
     */
    boolean useDefaultFilters() default true;
    /**
     * 指定某些定義Filter滿足條件的組件
     * @return
     */
    Filter[] includeFilters() default {};
    /**
     * 排除某些過來器掃描到的類
     * @return
     */
    Filter[] excludeFilters() default {};
    /**
     * 掃描到的類是都開啓懶加載 ,默認是不開啓的
     * @return
     */
    boolean lazyInit() default false;
}

基於xml配置:

<context:component-scan base-package="com.youzan" use-default-filters="false">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

基於JavaConfig配置:

@Configuration
@ComponentScan(value = "com.youzan", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
})
public class ScanConfig {
    
}

總結:@ComponentScan通常與@Configuration一起配合使用,相當於xml裏面的<context:component-scan>,用來告訴Spring需要掃描哪些包或類。如果不設值的話默認掃描@ComponentScan註解所在類的同級類和同級目錄下的所有類,所以對於一個Spring Boot項目,一般會把入口類放在頂層目錄中,這樣就能夠保證源碼目錄下的所有類都能夠被掃描到。

2.4 @EnableAutoConfiguration

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章