《SpringBoot揭秘:快速构建微服务体系》—第3章3.2节@SpringBootApplication背后的秘密

3.2 @SpringBootApplication背后的秘密
@SpringBootApplication是一个“三体”结构,实际上它是一个复合Annotation:

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

虽然它的定义使用了多个Annotation进行元信息标注,但实际上对于SpringBoot应用来说,重要的只有三个Annotation,而“三体”结构实际上指的就是这三个Annotation:
@Configuration
@EnableAutoConfiguration
@ComponentScan
所以,如果我们使用如下的SpringBoot启动类,整个SpringBoot应用依然可以与之前的启动类功能对等:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class DemoApplication {

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

但每次都写三个Annotation显然过于繁琐,所以写一个@SpringBoot-Application这样的一站式复合Annotation显然更方便些。
3.2.1 @Configuration创世纪
这里的@Configuration对我们来说并不陌生,它就是JavaConfig形式的Spring IoC容器的配置类使用的那个@Configuration,既然SpringBoot应用骨子里就是一个Spring应用,那么,自然也需要加载某个IoC容器的配置,而SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,很明显,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类!
很多SpringBoot的代码示例都喜欢在启动类上直接标注@Configuration或者@SpringBootApplication,对于初接触SpringBoot的开发者来说,其实这种做法不便于理解,如果我们将上面的SpringBoot启动类拆分为两个独立的Java类,整个形势就明朗了:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class DemoConfiguration {
    @Bean
    public Controller controller() {
        return new Controller();
    }
}

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

所以,启动类DemoApplication其实就是一个标准的Standalone类型Java程序的main函数启动类,没有什么特殊的。
而@Configuration标注的DemoConfiguration定义其实也是一个普通的JavaConfig形式的IoC容器配置类,没啥新东西,全是Spring框架里的概念!
3.2.2 @EnableAutoConfiguration的功效
@EnableAutoConfiguration其实也没啥“创意”,各位是否还记得Spring框架提供的各种名字为@Enable开头的Annotation定义?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和“做事方式”其实一脉相承,简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义:
@EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器。
@EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器。
而@EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器,仅此而已!
@EnableAutoConfiguration作为一个复合Annotation,其自身定义关键信息如下:

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

其中,最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器,就跟一只“八爪鱼”一样(如图3-1所示)。
借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以“智能”地自动配置功效才得以大功告成!

自动配置的幕后英雄:SpringFactoriesLoader详解
SpringFactoriesLoader属于Spring框架私有的一种扩展方案(类似于Java的SPI方案java.util.ServiceLoader),其主要功能就是从指定的配置文件META-INF/spring.factories加载配置,spring.factories是一个典型的java properties文件,配置的格式为Key = Value形式,只不过Key和Value都是Java类型的完整类名(Fully qualified name),比如:
example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
然后框架就可以根据某个类型作为Key来查找对应的类型名称列表了:

public abstract class SpringFactoriesLoader {
    // ...
    public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
        ...
    }

    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        ...
    }
    // ...
}

对于@EnableAutoConfiguration来说,SpringFactoriesLoader的用途稍微不同一些,其本意是为了提供SPI扩展的场景,而在@EnableAutoConfiguration的场景中,它更多是提供了一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdmin- JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.PropertyPlaceholderAuto- Configuration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAuto-Configuration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationProperties-AutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceException-TranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.Cassandra-DataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.Cassandra-RepositoriesAutoConfiguration,\
...
以上是从SpringBoot的autoconfigure依赖包中的META-INF/spring.factories配置文件中摘录的一段内容,可以很好地说明问题。
所以,@EnableAutoConfiguration自动配置的魔法其实就变成了:从classpath中搜寻所有META-INF/spring.factories配置文件,并将其中org.spring-framework.boot.autoconfigure.EnableAutoConfiguration对应的配置项通过反射(Java Reflection)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。
目前为止,还是Spring框架的原有概念和支持,依然没有“新鲜事”!
3.2.3 可有可无的@ComponentScan
为啥说@ComponentScan是可有可无的?因为原则上来说,作为Spring框架里的“老一辈革命家”,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件或bean定义,最终将这些bean定义加载到容器中。加载bean定义到Spring的IoC容器,我们可以手工单个注册,不一定非要通过批量的自动扫描完成,所以说@ComponentScan是可有可无的。
对于SpringBoot应用来说,同样如此,比如我们本章的启动类:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class DemoApplication {

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

如果我们当前应用没有任何bean定义需要通过@ComponentScan加载到当前SpringBoot应用对应使用的IoC容器,那么,除去@ComponentScan的声明,当前SpringBoot应用依然可以照常运行,功能对等!
看,还是没有啥新东西!

时间: 2024-10-12 11:45:07

《SpringBoot揭秘:快速构建微服务体系》—第3章3.2节@SpringBootApplication背后的秘密的相关文章

《SpringBoot揭秘:快速构建微服务体系》—第1章1.4节微服务会带来哪些挑战

1.4 微服务会带来哪些挑战微服务给我们带来的并非只有好处,还有相应的一些挑战.服务"微"化之后,一个显著的特点就是服务的数量增多了.如果将软件开发和交付也作为一种生产模式看待,那么数量众多的微服务实际上就类似于传统生产线上的产品,而在传统生产模型下,为了能够高效地生产大量产品,通常采用的就是标准化生产.比如在汽车产业,在福特T型车没有出来之前,大多汽车企业的生产效率都不高,而福特在引入标准化生产线之后,福特T型车得以大量生产并以低成本优势快速普及.在其他行业也是同样的道理,个性化生产

《SpringBoot揭秘:快速构建微服务体系》目录—导读

前 言为什么写这本书忘了是2015年的哪一天,只记得几个朋友跟友商的其他几个做技术的朋友吃饭,并简单做下技术交流.席间,友商的几位朋友对SpringBoot框架实施微服务很感兴趣,交谈甚欢之际,我无意间开玩笑说:"是不是该考虑写一本SpringBoot的书?"钟伦甫(原淘宝聚石)同学随口一句,"你倒是写啊!",得,以行践言吧,谁让你把话说出去了呢?当然,朋友的"热切期盼"只是其一,微服务盛行也是本书写作的一个契机, 希望本书成为国内第一本微服务相

《SpringBoot揭秘:快速构建微服务体系》—第1章1.1节了解微服务

第1章 了解微服务SpringBoot是一个可使用Java构建微服务的微框架,所以在了解SpringBoot之前,我们需要先了解什么是微服务.1.1 什么是微服务微服务(Microservice)虽然是当下刚兴起的比较流行的新名词,但本质上来说,微服务并非什么新的概念.实际上,很多SOA实施成熟度比较好的企业,已经在使用和实施微服务了.只不过,它们只是在闷声发大财,并不介意是否有一个比较时髦的名词来明确表述SOA的这个发展演化趋势罢了.微服务其实就是服务化思路的一种最佳实践方向,遵循SOA的思路

《SpringBoot揭秘:快速构建微服务体系》—第1章1.3节微服务会带来哪些好处

1.3 微服务会带来哪些好处显然,随着系统复杂度的提升,以及对系统扩展性的要求越来越高,微服务化是一个很好的方向,但除此之外,微服务还会给我们带来哪些好处?1.3.1 独立,独立,还是独立我们说微服务打响的是各自的独立战争,所以,每一个微服务都是一个小王国,这些微服务跳出了"大一统"(Monolith)王国的统治,开始从各个层面打造自己的独立能力,从而保障自己的小王国可以持续稳固的运转.首先,在开发层面,每个微服务基本上都是各自独立的项目(project),而对应各自独立项目的研发团队

《SpringBoot揭秘:快速构建微服务体系》—第3章3.3节SpringApplication:SpringBoot程序启动的一站式解决方案

3.3 SpringApplication:SpringBoot程序启动的一站式解决方案 如果非说SpringBoot微框架提供了点儿自己特有的东西,在核心类层面(各种场景下的自动配置一站式插拔模块,我们下一章再重点介绍),也就是SpringApplication了. SpringApplication将一个典型的Spring应用启动的流程"模板化"(这里是动词),在没有特殊需求的情况下,默认模板化后的执行流程就可以满足需求了:但有特殊需求也没关系,SpringApplication在

《SpringBoot揭秘:快速构建微服务体系》—第1章1.5节本章小结

1.5 本章小结在带领大家探索本书的主角SpringBoot微框架之前,本章首先为大家介绍了SpringBoot微框架服务的核心场景,即微服务.然后一起探索了微服务的概念以及由来,并探讨了微服务可以为我们带来哪些好处,以及同时又为我们带来哪些挑战.总的来说,微服务化虽然是当下流行的趋势,但并非任何场景都合适,我们还是要审慎地在"大一统"(Monolith)服务架构和微服务架构之间做出选择, 而一旦确定选择了微服务化之路,那么,就应该围绕团队和组织的主要语言生态以及微服务方向积极探索高效

《SpringBoot揭秘:快速构建微服务体系》—第2章2.1节Spring框架的起源

第2章 饮水思源:回顾与探索Spring框架的本质SpringBoot框架的命名关键在"Boot"上,或许Boot Spring更能说明这个微框架设计的初衷,也就是快速启动一个Spring应用!所以,自始至终,SpringBoot框架都是为了能够帮助使用Spring框架的开发者快速高效地构建一个个基于Spring框架以及Spring生态体系的应用解决方案.要深刻理解SpringBoot框架,首先我们需要深刻理解Spring框架,所以让我们先来读读历史吧!2.1 Spring框架的起源虽

《SpringBoot揭秘:快速构建微服务体系》—第3章3.4节再谈自动配置

3.4 再谈自动配置此前我们讲到,@EnableAutoConfiguration可以借助SpringFactoriesLoader这个特性将标注了@Configuration的JavaConfig类"一股脑儿"的汇总并加载到最终的ApplicationContext,不过,这其实只是"简化版"的说明,实际上,基于@EnableAutoConfiguration的自动配置功能拥有更加强大的调控能力,通过配合比如基于条件的配置能力或者调整加载顺序,我们可以对自动配置进

《SpringBoot揭秘:快速构建微服务体系》—第2章2.3节 了解一点儿JavaConfig

2.3 了解一点儿JavaConfig Java 5的推出,加上当年基于纯Java Annotation的依赖注入框架Guice的出现,使得Spring框架及其社区也"顺应民意",推出并持续完善了基于Java代码和Annotation元信息的依赖关系绑定描述方式,即JavaConfig项目. 基于JavaConfig方式的依赖关系绑定描述基本上映射了最早的基于XML的配置方式,比如: (1)表达形式层面 基于XML的配置方式是这样的: <!-- bean定义 --> 而基于