Spring Boot 启动过程分析

作者: 徐志毅 | 来源:发表于2018-05-27 22:21 被阅读220次

    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

    相关文章

      网友评论

      • 天蝎小妖:谢谢,作者非常认真,文章分析得非常详细,通俗易懂

      本文标题:Spring Boot 启动过程分析

      本文链接:https://www.haomeiwen.com/subject/ohbijftx.html