关于后端:从-SpringBootApplication-入手理解-Spring-注解驱动编程

32次阅读

共计 6295 个字符,预计需要花费 16 分钟才能阅读完成。

前言

简直所有的 Spring Boot 利用都会在启动类上增加 @SpringBootApplication,能够说它是 Spring Boot 利用最外围的注解了。Spring Boot 基于 Spring Framework,@SpringBootApplication 也不例外,这篇心愿在了解 @SpringBootApplication 的根底上将 Spring 注解的内容进行串联,以便达到死记硬背的成果。

了解 @SpringBootApplication 语义

即使初学者不了解 @SpringBootApplication,通常来说也会把这个注解增加到启动类,而后将启动类放在根包上面。

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

}

能够说下面的代码,就是 Spring Boot 利用的一个模板,所有的 Spring Boot 利用都有相似的代码。

对于 @SpringBootApplication 的注解语义,Spring 官网在“3.6 Using the @SpringBootApplication Annotation”形容如下:

许多 Spring Boot 开发者喜爱在他们的利用中应用主动拆卸、组件扫描以及在配置类上定义额定的配置。单个 @SpringBootApplication 注解曾经用来启动这三个个性,即:

EnableAutoConfiguration:启用 Spring Boot 主动拆卸机制。

@ComponentScan:启用利用中包上面的 @Component 扫描性能。

@Configuration:容许在上下文中注册 bean 或导入额定的配置类。

也就是说 @SpringBootApplication 相当于三个注解的组合,咱们来看下这个注解的定义。

/**
 * @since 1.4.0
 */
@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 {... 省略属性}

能够看到 @SpringBootApplication 被 @EnableAutoConfiguration、@ComponentScan 及 @SpringBootConfiguration 同时标注。

那么官网形容的 @Configuration 在哪呢?依据直觉咱们看下 @SpringBootConfiguration。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {... 省略属性}

能够看到 @SpringBootConfiguration 被 @Configuration 标注,因而 Spring 官网提到 @Configuration 注解。

不过 @SpringBootApplication 中的 @ComponentScan 注解并没有应用默认的属性配置,而是指定了 excludeFilters 属性值用来过滤扫描的组件,TypeExcludeFilter 依据用户自定义的 TypeExcludeFilter bean 过滤组件,AutoConfigurationExcludeFilter 用于跳过主动拆卸的配置类。

事实上,@SpringBootApplication 这个注解也不是在最后的版本就有的,而是在 Spring Boot 1.4 版本增加到 Spring Boot 框架中的,在此之前只能应用组合 @SpringBootApplication 注解的三个注解,它们的语义是保持一致的,如下所示。

@Configuration
@ComponentScan
@EnableAutoConfiguration
//@SpringBootApplication
public class SpringBootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringBootDemoApplication.class, args);
    }

}

因为 @Configuration、@ComponentScan、@EnableAutoConfiguration 这三个注解应用较为频繁 Spring 官网才将其组合到一个注解中。

Spring 注解编程模型

注解作为元数据,只有被读取到能力施展其作用,那么 Spring Boot 如何读取 @SpringBootApplication 注解的呢?

将 @SpringBootApplication 注解标注的 class 传入 SpringApplication.run 办法的参数后,Spring Boot 便会将这个 class 注册为 bean,之后 Spring 便会对这个 bean 进一步的解决,例如依据 @ComponentScan 进行组件扫描,依据 @EnableAutoConfiguration 进行主动拆卸。

这也意味着不用肯定要把 @SpringBootApplication 增加到启动类,如果咱们想把 @SpringBootApplication 增加到其余配置类,咱们能够如下更改。

public class Config {
}

public class SpringBootDemoApplication {public static void main(String[] args) {SpringApplication.run(Config.class, args);
    }

}

事实上,@SpringBootApplication 只是将多个注解标注到本身,Spring Boot 也没有对这个注解做额定的解决,咱们甚至能够自定义一个注解代替 @SpringBootApplication,示例如下。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface CustomSpringBootApplication {
}

@CustomSpringBootApplication
public class SpringBootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringBootDemoApplication.class, args);
    }

}

上述咱们自定义的 @CustomSpringBootApplication 注解能够达到相似 @SpringBootApplication 注解的成果,这得益于 Spring 的注解编程模型,其中一些概念如下。

  1. 注解与元注解

标注在注解上的注解称为元注解,例如 @ComponentScan 注解标注在了 @SpringBootApplication 注解上,@ComponentScan 是 @SpringBootApplication 注解的元注解,同时称 @SpringBootApplication 被 @ComponentScan 注解元标注。

  1. 组合注解

被一个或多个注解标注的注解被称为组合注解,如 @SpringBootApplication 注解,组合注解的目标在于组合多个注解具备的性能。

例如 @SpringBootApplication 主动具备组件扫描、配置类、启动主动拆卸的性能。Spring 中的注解容许多层次“继承”,例如 @Configuration 标注了 @SpringBootConfiguration,@SpringBootConfiguration 又标注了 @SpringBootApplication,因而 @SpringBootApplication 标注的类成为一个配置类。

  1. 属性别名与属性重写

属性别名用于将一个属性指定为另一个属性的别名。应用 @AliasFor 注解进行标注。例如 Spring MVC 中的 @RequestMapping 注解。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {@AliasFor("path")
 String[] value() default {};

 @AliasFor("value")
 String[] path() default {};}

path 和 value 属性上都标注了 @AliasFor 注解,它们互为对方的别名,应用时指定其中一个属性值即可,如果应用指定多个产生歧义则会报错。

因为注解不反对继承,用户无奈间接指定元注解中的属性值,Spring 注解编程模型容许注解中的属性重写元注解中的属性。注解中的属性名称与元注解中的属性名称统一即可重写元注解属性,如果不统一还能够应用 @AliasFor 注解标注在注解属性上用来指定重写哪个元注解的哪个属性。例如对于 @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 = ComponentScan.class, attribute = "basePackages")
 String[] scanBasePackages() default {};}

@SpringBootApplication 注解的 scanBasePackages 属性就重写了元注解 @ComponentScan 的 basePackages 属性。

Spring 组件扫描
@SpringBootApplication 注解上标注了 @ComponentScan 注解,因而 @SpringBootApplication 可用于扫描组件,那么扫描组件的动作产生在什么时候呢?Spring 又是如何进行组件扫描的?

要了解 Spring 的组件扫描,还得看 Spring 的实质与历史。Spring 实质上只是一个治理 bean 的容器,并提供了依赖注入与依赖获取的能力,因而须要定义哪些 bean 交给 Spring 容器进行治理。

Spring 诞生初期,Java 注解还未诞生,Spring 采纳业界宽泛应用的 xml 作为配置文件。Spring 1.2 版本,第一个注解 @Transactiona l 诞生。到了 2.5 版本,Spring 才开始反对在 xml 配置 <context:component-scan> 对类门路下进行扫描,并将标注了 @Component 的类注册为 bean。到了 Spring 3.0 版本,@Configuration 注解诞生,此时只能配合 @Import、@ImporResource 或者 @Bean 注解无限的配置一些 bean。直到 Spring 3.1 版本,@ComponentScan 注解才诞生,并提供了基于注解的 ApplicationContext 实现 AnnotationConfigApplicationContext。

回到 Spring 对类门路下的组件扫描,流程大略如下,当应用 <context:component-scan> 或间接应用基于注解的 ApplicationContext 对类门路扫描后,Spring 会查找符合条件的组件类,并将满足条件的这些类注册为 Spring bean,包含满足 @Conditional 及 @ComponentScan#excludeFilter 条件。而后应用 ConfigurationClassPostProcessor 在利用上下文的生命周期 bean 实例化前的阶段对配置类进一步的解决,配置类包含标注或元标注了 @Component、@ComponentScan、@Import 或 @ImportResource 注解的组件类,或存在 @Bean 注解的办法的组件类。

Spring Boot 将 @SpringBootApplication 标注的类注册为 bean 之后,ConfigurationClassPostProcessor 就会对这个类进一步解决了,当发现存在注解或元注解 @ComponentScan 就会进一步解决,扫描并注册 bean。

Spring Boot 主动拆卸
前文提到应用 @SpringBootApplication 注解后会主动开启主动拆卸性能,正是因为 @SpringBootApplication 被 @EnableAutoConfiguration 标注。

@EnableAutoConfiguration 应用了 Enable* 编程模型,次要利用 @Import 及 @Conditional 依据某些条件自动化拆卸一些 bean。

主动拆卸能够了解为当某些条件满足后 Spring 会主动注册一些 bean,而不须要手动进行配置。例如,当咱们增加 spring-boot-starter-web 依赖后,Spring Boot 发现类门路下存在 Tomcat,就会主动注入一些 Web 相干的 bean,从而简化用户的配置。

如果 Spring Boot 未提供主动拆卸性能,咱们则只能通过 @Enable* 编程模型手动的将某些功能模块的 bean 进行注册,Spring Boot 将一些与业务无关的 bean 的拆卸工作简化到 @EnableAutoConfiguration 注解后堪称是大大降低了 Spring Boot 的上手门槛。

作为 Spring Boot 外围个性的主动拆卸,咱们这里先简略了解,上面会对其独自介绍。

总结
这篇咱们在介绍 @SpringBootApplication 的根底上,介绍了无关这个注解更底层的一些内容,包含注解编程模型、组件扫描、主动拆卸。

正文完
 0