前言
Spring Boot为我们提供了非常优雅的开箱即用特性,然后Spring Cloud基于这个特性将J2EE生态中的众多组件进行了包装,让我们在使用的时候不用关心太多组件整合引入上的问题。在这之前,大到我们在tomcat容器中引入Spring、SpringMVC、Redis、MySQL等各种数据库或者中间件,小到引入Json或者各种工具类等,都要进行比较繁琐的xml配置,而且动不动就造成各种各样的依赖缺失或者冲突等。然而这一切到Spring Boot中好像有了很大的不同,似乎我只要加几个简单的注解,配置一些必要的property,就可以启动一个完整的web应用,其过程和体验感觉十分的“丝滑”,组合框架变得就像搭积木那样简单。至于这些都是怎么做到的呢?接下来就一一道来。
4.1 @EnableAutoConfiguration注解
Spring Boot中提供@EnableAutoConfiguration注解支持,整个开箱即用的自动配置核心就依托于此了。该注解被“@Import(AutoConfigurationImportSelector.class)”标注,在第三章中有介绍到这个扩展机制。这个Selector 的selectImports实现方法中有一个关键的过程:
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
在这里我们又一次看到了在第一章中介绍的“SpringFactoriesLoader”,可以回顾相关章节。getSpringFactoriesLoaderFactoryClass()方法返回的是EnableAutoConfiguration.class,在这里以spring-boot-autoconfigure包中的spring.factories举例:
这里就是关于@EnableAutoConfiguration注解自动引入BeanDefinition配置的SPI扩展机制了,声明在spring.factories文件中的“org.springframework.boot.autoconfigure.EnableAutoConfiguration”所指示的class都会被spring当做BeanDefinition的配置去加载,同时结合@Conditional机制,选择性地注入到Spring容器中,从而实现自动配置和整合的功能。所以如果我们自己的功能组件按照这样的模式开发,在Spring Boot应用中就可以无缝地集成进来,要关心的也就是功能组件所需要的必要property信息。
在Spring Framework中其实也提供了NamespaceHandler这个机制来提供对xml配置文件解析的扩展,简化xml中bean的配置,比如我们常见的“mvc”命名空间下的标签。所以感觉这两种简化引入bean定义的方式应该算是相辅相成的。
4.2 Starters
在Spring Boot中,引入某个组件更多的是通过在maven中添加“xxx-starter”来引入的。在这些starter中,也许并没有任何代码或者配置文件。Spring其实是利用了maven的依赖传递特性维护了不同组件各自所需要的依赖项罢了,它把这些依赖通过starter统一整理成一个更大一些的依赖集合,使得我们无须再一一寻找相关依赖,然后再结合EnableAutoConfiguration机制将组件进行配置并注入到容器中,开箱即用由此而生。例如spring boot starter的依赖关系如下:
Spring Boot为我们准备了web应用中常见的数据库访问、log、序列化等starter,为我们又做了一切它能做的准备工作,让我们更方便地整合它们,省去我们重复性的工作。这样的特性真的十分诱人!!
4.3 @SpringBootApplication
在我们第一章中的示例代码中,用来启动程序的Class上面使用了@SpringBootApplication注解,现在我们就可以拆分这个注解的功能了,这个注解是个被嵌套标注的,嵌套结构如下图:
Spring Boot早期的版本还没有这个注解,如果在别人代码里遇到其他相关功能的注解,我们也就都能明白其作用了。结合前面文章所介绍的原理知识,我们头脑中应该对我们的程序是如何启动,如何去扫描Bean,以及如何整合其他引入的组件的机制有一个很清楚的认识了。同时,如果我们需要开发一个自定义的组件,我想,我们也能给出一个符合Spring Boot设计思想的合理解决方案。例如,写一个自定义的starter,在自动配置的时候是使用EnableAutoConfiguration机制还是ApplicationContextInitializer机制,在扫描Bean的时候是使用Impor机制还是Configuration或者ImportResource等等。
小结
其实Spring Boot为我们做了很多准备工作,所以可以用很简单的几行代码就可以启动一个web服务,相比于曾经需要自己查阅各种文档来整合框架然后打包部署tomcat来说,确实很有诱惑力。