Spring Boot开发实战
上QQ阅读APP看书,第一时间看更新

2.4 Spring Boot应用注解@Spring BootApplication

我们在上面看到在Spring Boot入口类上面添加了注解@Spring BootApplication,这个注解的定义如下:

        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Inherited
        @Spring BootConfiguration
        @EnableAutoConfiguration
        @ComponentScan(excludeFilters = {
                @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
                @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExclu
                    deFilter.class) })
        public @interface Spring BootApplication {...}

@Spring BootApplication注解实际上封装了以下三个注解:

❑@Spring BootConfiguration:配置类注解。

❑@EnableAutoConfiguration:启用自动配置注解。

❑@ComponentScan:组件扫描注解。

下面我们分别来介绍。

2.4.1 Spring Boot配置类注解

@SpringBootConfiguration与@Component注解是一样的。@SpringBootConfiguration其实是Spring Boot包装的@Configuration注解:

        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Configuration
        public @interface Spring BootConfiguration {
        }

而@Configuration注解使用的又是@Component注解:

        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Component
        public @interface Configuration {
            @AliasFor(annotation = Component.class)
            String value() default "";
        }

我们知道,@Component注解的功能是把普通POJO实例化到Spring容器中,相当于配置文件中的<bean id = ""class = ""/>。

在类上添加注解@Configuration,表明这个类代表一个Spring配置文件,与原来XML配置是等效的。只不过现在用Java类加上一个@Configuration注解进行配置了,这种方式与XML相比可以称得上是极简风格了。同时基于注解的配置风格,使得代码的可读性也大大增高了。

Spring容器可以扫描出任何我们添加了@Component注解的类,Bean的注册逻辑在Class-PathScanningCandidateComponentProvider这个类的registerDefaultFilters方法里。

提示

注解(Annotation)是JDK1.5中引入的一个新特性。从Spring2.0以后的版本中,Spring引入了基于注解方式的配置,用于取代XML配置文件,从而极简化了Bean的配置,Spring后来的新版本。在Spring Boot中完全采用基于注解(Spring4.x引入了更加智能的@Condition系列注解,我们将会在后面的章节中详细介绍)的配置,实现“零XML的配置”(当然,同时也支持之前的XML配置文件方式)。

2.4.2 启用自动配置注解

@EnableAutoConfiguration这个注解是Spring Boot的最核心注解。首先我们看它的定义:

        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Inherited
        @AutoConfigurationPackage
        @Import(AutoConfigurationImportSelector.class)
        public @interface EnableAutoConfiguration {...}

其中,导入配置类注解@Import标识导入@Configuration标注的配置类。@Import用来整合所有在@Configuration注解中定义的Bean配置。这与我们将多个XML配置文件导入到单个文件的场景一致。@Import注解实现了相同的功能。

使用@EnableAutoConfiguration注解可以启用Spring应用程序上下文的自动配置,Spring Boot会去尝试猜测和配置你可能需要的Bean。自动配置类通常是根据类路径中你定义的Bean来推断可能需要怎样的配置。

例如,如果在你的类路径中有tomcat-embedded.jar这个类库,那么Spring Boot会根据此信息来判断你可能需要一个TomcatServletWebServerFactory(除非你已经定义了你自己的ServletWebServerFactory Bean)。当然我们还可以通过设置exclude或者excludeName变量的值来手动排除你不想要的自动配置。

Spring Boot默认扫描的包路径是入口类Demo0HelloWorldApplication所在的根包中,及其所有的子包。通常,Spring Boot自动配置Bean是根据Conditional Bean(条件Bean)中注解的类信息来推断的。例如@ConditionalOnClass、@ConditionalOnMissingBean注解。关于Spring Boot自动配置的相关内容我们将在后面的章节中详细介绍。

2.4.3 组件扫描注解

组件扫描注解@ComponentScan提供的功能与Spring XML配置文件中的<context:component-scan>元素等价。对应@ComponentScan注解的处理类是ConfigurationClassParser。@ComponentScan告诉Spring去哪个package下面扫描Spring注解。Spring会去自动扫描这些被Spring注解标注的类,并且将其注册到Bean容器中。例如下面的XML配置:

        <beans>
            <context:component-scan base-package="com.easy.SpringBoot"
                name-generator="com.easy.SpringBoot.MyApp" />
        </beans>

对应到Java Config风格如下:

        @Configuration
        @ComponentScan(basePackages = "com.easy.SpringBoot", nameGenerator = MyApp.class)
        public class AppConfig {
              .
        }

如果你有个类用@Controller注解标识了,但是没有加上@ComponentScan告诉Spring去扫描这个类所在的包,那么该Controller就不会被注册到Spring容器中。

不过,Spring Boot中如果不显式地使用@ComponentScan指明对象扫描的包,那么默认只扫描当前启动类所在的包里的类。

我们可以设置basePackageClasses的值来指定要扫描哪个类所在的包,代码示例如下:

        @Spring BootApplication
        @ComponentScan(basePackageClasses=MyApplication.class) //指定扫描MyApplication
                                                                    //类所在的包
        public class MyApplication {
            public static void main(String[] args){
                SpringApplication.run(MyApplication.class, args);
            }
        }