Spring Boot教程(8) – 理解注解@SpringBootApplication

上一篇文章说了说Spring容器的作用,这次趁热打铁,看看Spring Boot中它是怎么起作用的。

有了Spring容器之后,开发的模式简化了很多,你的注意力基本只需要集中在编写Bean上,比如@Controller类呀,@Service类呀,@Repository类呀等等。你新建了一个Spring Boot应用之后,随便编写一个控制器(Controller),他就可以用来处理网络请求了。按理说,一个控制器成为容器中的Bean,得有@ComponentScan来扫描呀,但是新建的应用也没看到有配置类,更不用说依靠在其之上的@ComponentScan注解了。这一些都要从@SpringBootApplication说起。

上图是很常见的Application类,用Spring Initializr生成的项目都有。它有个@SpringBootApplication注解,这个注解提供了Spring Boot的很多关键特性。我们打开SpringBootApplication的源码看一看:

@SpringBootApplication是个组合注解(composed annotation),用它就相当于同时用了下面三个注解:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

Spring提供的很多注解都是元注解,组合注解就是由一个或者多个元注解组合成的。比方说@RestController,你写纯API服务的时候,控制器一般都用上它,它是由@Controller和@ResponseBody组合而成的,你直接把@RestController替换成这两个,是可以的,他们是等效的。

如果你细心的话,会发现@Controller也是一个组合注解,元注解是@Component,所以说为什么组件扫描能扫描到@Controller,原因就在这里。

一个注解可能是元注解,也可能是组合注解,它俩只是个相对的概念。实际开发中,如果你的一个组件类加了好多注解,不妨自己去创建一个新的组合注解,这样更清晰简洁。更多相关内容,你可以看看Spring文档里关于元注解和组合注解的详细说明

废了这么多口舌,我就是想告诉你@SpringBootApplication目的就是为了方便地引入它的三个元注解

刚才我们说到了@ComponentScan,它用来告诉Spring容器去扫描组件,但是去哪里扫描呢?它有一个String[]类型的注解参数basePackages,可以传入需要扫描的路径,如果你不传,那就以当前类的包作为路径。所以这么一来,你的Application类在哪个包里,自动扫描就在哪个包里扫。你只要在这个包或者子包里编写@Controller类或者其他@Component类,都会被扫到的。假设你的Application类所在的包为com.fookwood.demo,那建议你所有的代码都放这个包下,省得因为组件没放入容器而出错。

我们知道@ComponentScan都是跟着配置类一起出现的,但是没见哪里有@Configuration呀?因为有@SpringBootConfiguration了,他是个组合注解,把@Configuration带来了。话说我找了很多资料,没有发现@SpringBootConfiguration到底有什么独特作用,它的注释上说一个程序通常只需要一个@SpringBootConfiguration就行了,而且大部分都是从@SpringBootApplication获取的。那干脆不管了,就当他是个@Configuration吧。

最后,该讨论下@EnableAutoConfiguration了。他开启了Spring Boot中最重要的特性—自动配置,自动配置可以根据你引入的依赖自动生成Bean等。大部分依赖都有对应一个叫做*AutoConfiguration的类,比如GSON有一个对应的GsonAutoConfiguration类:

看图,他是一个正常的配置类,有@Configuration注解,但是呢,它的方法提供的Bean并不是直接加到容器里的,而是需要满足一定条件才行。条件呢,通过@Conditional* 注解提供,GsonAutoConfiguration使用了@ConditionalOnClass注解,它的参数是Gson.class,意思就是,当类路径中有Gson这个类的时候,GsonAutoConfiguration才是一个真正的配置类。图中的gsonBuilder方法新建了一个GsonBuilder对象,如果容器里没有这个类型的Bean,就使用新建的这个对象。图中的gson方法,新建了一个Gson对象,如果容器里没有Gson类型的Bean,就把这个对象放进去。

所以说,一旦你在build.gradle中添加了GSON的依赖,那么你就可以直接在自己的代码里引入Gson对象了,省事儿不?你要是想定义自己的Gson对象,当然可以,你可以在自己的配置类,添加你自己的GsonBuilder对象或者Gson对象,这样的话,自动配置判断容器里已经有了,@Conditional*的条件不成立,就不自己搞了。

再提一句吧,虽然你的Application类(比如本文最上面的WhatEverApplication)也是一个配置类,你可以添加方法来创建新的Bean,不过我不喜欢这么这么做,我通常是新建单独的配置类,比如新建一个名为WebConfig的类,在这个类里定义Web开发相关的Bean。

发表评论

电子邮件地址不会被公开。