当前位置: 首页 > 后端技术 > Java

从@SpringBootApplication入手,了解Spring注解驱动编程

时间:2023-04-02 10:22:28 Java

前言几乎所有的SpringBoot应用都会在启动类中添加@SpringBootApplication,可以说是SpringBoot应用的核心注解。SpringBoot基于SpringFramework,@SpringBootApplication也不例外。本文希望在了解@SpringBootApplication的基础上,将Spring注解的内容串联起来,达到一个综合的效果。理解@SpringBootApplication的语义即使初学者不理解@SpringBootApplication,通常也会在启动类上加上这个注解,然后将启动类放在根包下。@SpringBootApplicationpublicclassSpringBootDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(SpringBootDemoApplication.class,args);}}可以说上面的代码是SpringBoot应用的模板,所有的SpringBoot应用都有类似的代码。关于@SpringBootApplication的注解语义,Spring官网在“3.6使用@SpringBootApplication注解”中是这样描述的:许多SpringBoot开发者喜欢在应用中使用自动组装、组件扫描、在配置类上定义额外的配置。已使用单个@SpringBootApplication注释来启用这三个功能,即:EnableAutoConfiguration:启用SpringBoot自动装配机制。@ComponentScan:在应用程序包下启用@Component扫描。@Configuration:允许在上下文中注册bean或导入额外的配置类。也就是说@SpringBootApplication相当于三个注解的组合。我们来看看这个注解的定义。/***@since1.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@interfaceSpringBootApplication{...propertiesomitted}可以看到@SpringBootApplication被@EnableAutoConfiguration、@ComponentScan和@SpringBootConfiguration标记同时。那么官网描述的@Configuration在哪里呢?让我们根据直觉看一下@SpringBootConfiguration。@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic@interfaceSpringBootConfiguration{...省略属性}可以看到@SpringBootConfiguration是用@Configuration注解的,所以Spring官网提到了@Configuration注解.但是@SpringBootApplication中的@ComponentScan注解并没有使用默认的属性配置,而是指定了excludeFilters属性值来过滤扫描到的组件。TypeExcludeFilter根据用户自定义的TypeExcludeFilterbean过滤组件,AutoConfigurationExcludeFilter用于跳过自动装配的配置。种类。事实上,@SpringBootApplication注解在原始版本中是不存在的,是在SpringBoot1.4中加入到SpringBoot框架中的。在此之前,只能使用三个结合@SpringBootApplication注解的注解。它们的语义是一致的,如下所示。@Configuration@ComponentScan@EnableAutoConfiguration//@SpringBootApplicationpublicclassSpringBootDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(SpringBootDemoApplication.class,args);}}由于@Configuration、@ComponentScan和@EnableAutoConfiguration这三个注解,Spring官方使用较多的是将其合为一个注解。Spring注解编程模型注解作为元数据,只有被读取才能发挥作用,那么SpringBoot是如何读取@SpringBootApplication注解的呢?将带有@SpringBootApplication注解的类传入SpringApplication.run方法的参数中后,SpringBoot会将该类注册为bean,然后Spring会进一步处理这个bean,比如根据@ComponentScan进行组件扫描,根据@EnableAutoConfiguration进行组件扫描用于自动装配。这也意味着不需要在启动类中添加@SpringBootApplication。如果我们想在其他配置类中加入@SpringBootApplication,可以这样改。公共类配置{}公共类SpringBootDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(Config.class,args);实际上,@SpringBootApplication只是给自己注解了多个注解,而SpringBoot还没有对这个注解进行额外的处理,我们甚至可以自定义一个注解来替代@SpringBootApplication,如下图。@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Configuration@EnableAutoConfiguration@ComponentScanpublic@interfaceCustomSpringBootApplication{}@CustomSpringBootApplicationpublicclassSpringBootDemoApplication{publicstaticvoidmain(StringDemoot[]args){SpringApplication.class,args);}}上面自定义的@CustomSpringBootApplication注解可以实现类似@SpringBootApplication注解的效果,这得益于Spring的注解编程模型,部分如下。Annotationsandmeta-annotations标注在注解上的注解称为元注解。例如,@ComponentScan注解是在@SpringBootApplication注解上进行注解。@ComponentScan是@SpringBootApplication注解的元注解。同时,据说@SpringBootApplication被@ComponentScan注解注解了。组合注解由一个或多个注解组成的注解称为组合注解,如@SpringBootApplication注解。复合注解的目的是将多个注解的功能组合起来。比如@SpringBootApplication自动具备组件扫描、配置类、自动组装等功能。Spring中的注释允许多级“继承”。比如@Configuration注解了@SpringBootConfiguration,@SpringBootConfiguration注解了@SpringBootApplication,那么@SpringBootApplication注解的类就变成了配置类。属性别名和属性覆盖属性别名用于将一个属性指定为另一个属性的别名。使用@AliasFor注释进行注释。例如SpringMVC中的@RequestMapping注解。@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Mappingpublic@interfaceRequestMapping{@AliasFor("path")String[]value()default{};@AliasFor("value")String[]path()default{};}path和value属性都用@AliasFor注解标注,它们互为别名,使用时指定其中一个属性值即可,如果使用多个指定值导致歧义then会报错。由于注解不支持继承,用户不能直接在元注解中指定属性值,而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@interfaceSpringBootApplication{@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作为配置文件。在Spring1.2版本中,诞生了第一个注解@Transactional。直到2.5版本,Spring才开始支持在xml配置中扫描类路径,将@Component标记的类注册为bean。在Spring3.0中,@Configuration注解诞生了。此时,只有部分bean可以使用有限的@Import、@ImporResource或@Bean注解进行配置。直到Spring3.1才诞生了@ComponentScan注解,并提供了基于注解的ApplicationContext实现AnnotationConfigApplicationContext。回到Spring对类路径下组件的扫描,大致流程如下。当使用或者直接使用基于注解的ApplicationContext扫描类路径时,Spring会找到满足条件的组件类,并将满足条件的这些类注册为Springbean,包括@Conditional和@ComponentScan#excludeFilter条件。然后使用ConfigurationClassPostProcessor在applicationcontext生命周期的bean实例化之前的阶段进一步处理配置类。配置类包括被@Component、@ComponentScan、@Import或@ImportResource注解注解或元注解的组件类,或者@Bean存在注解方法的组件类。SpringBoot将@SpringBootApplication注解的类注册为bean后,ConfigurationClassPostProcessor会进一步处理这个类。当找到注解或元注解@ComponentScan时,它将进一步处理、扫描和注册bean。SpringBoot自动组装前面提到,使用@SpringBootApplication注解后会自动开启自动组装功能,正是因为@SpringBootApplication被@EnableAutoConfiguration注解了。@EnableAutoConfiguration使用Enable*编程模型,主要是利用@Import和@Conditional根据一定的条件自动组装一些bean。自动装配可以理解为Spring会在满足一定条件时自动注册一些bean,不需要手动配置。例如,当我们添加spring-boot-starter-web依赖时,SpringBoot发现classpath中存在Tomcat,会自动注入一些Web相关的bean,从而简化用户配置。如果SpringBoot没有提供自动组装功能,我们只能通过@Enable*编程模型手动注册一些功能模块的bean。SpringBoot将一些与业务无关的bean的组装简化为@EnableAutoConfiguration注解。大大降低了SpringBoot的入门门槛。作为SpringBoot核心特性的自动组装,我们在这里简单了解一下,下面单独介绍。综上所述,本文在介绍@SpringBootApplication的基础上,介绍了该注解的一些底层内容,包括注解编程模型、组件扫描、自动装配等。