@Configuration
所在包:org.springframework.context.annotation
所在 jar:spring-context.jar(5.1.6.RELEASE)
用于进行配置,修饰类,标示某一个类是配置类。
源码
标识一个 java 类声明了一个或者多个被 @Bean 注解标示的方法,而且可以被 Spring 的容器进行处理,生成 Bean 的定义,以及针对于运行期的 Bean 服务请求。
Java Config 实现方式
@Configuration 类通常是要么通过 AnnotationConfigApplicationContext ,要么通过 AnnotationConfigWebApplicationContext 来启动、实现的。
针对之前的代码的一个简单实例:
首先创造一个 AnnotationConfigApplicationContext 应用上下文的实例,接着把 Java Config 配置类注册到应用上下文当中,刷新应用上下文以后就可以通过 getBean 方法获取(从 Spring 容器内)之前定义好的 MyBean 实例,根据后面的请求,进行 MyBean 操作。
这也解释了,我们在 Spring Boot 应用当中,所有的 Java 配置类,怎么就能被 Spring Boot 或者 Spring 找到的。
Xml 实现方式
传统方式,在 Java Config 兴起以前,当时的标准就是使用 xml 来实现配置。在 Spring Boot 当中也是支持 xml 方式的,但是很少会这么用,通常都是使用注解方式。
xml 方式必须要加上上面的命名空间,才能起效果。
@ComponentScan
组件扫描注解,修饰 @SpringBootApplication 注解。这个注解,主要是扫描应用的所有组件。
对于 Spring Boot 应用来说,常常会把包含 main 方法的这个类,也就是启动类,定义在一个包的最顶层。其他的控制器、服务层、数据层、组件层都定义在启动类的子包里。
因为根据注解扫描原则,注解会扫描这个包本身以及这个包的所有子包。所以一般 Spring Boot 的启动类都是位于整个应用的最顶层,应用的其他文件都在它的子包内。
使用环境 API
外部的值,可以通过把 org.springframework.core.env.Environment 组件注入到 @Configuration 所在的类当中,从而使用它们。
比如使用自动装配注解来注入:
@Autowired
自动装配注解,自动装配到所需的类里面。
这里的 env 被 @Autowired 自动装配到 AppConfig 类里,而 myBean 的 name 值就是通过 env.getProperty("bean.name")
的方式来获取的外部值。
@PropertySource
属性源注解。通过环境对象(Environment)去解析的属性位于一个或者多个 属性源(property source)对象当中,而且被 @Configuration 修饰的类还可以通过使用 @PropertySource 注解贡献属性源(property source)到环境对象(Environment)中。
也就是说,只要通过 @PropertySource 指定了外部文件,那么就可以使用外部文件里面的值了。
例如上面的 bean.name
就是定义在 classpath:/com/acme/app.properties 外部文件里面的值。
@Value
值注解。外部的值可以通过值注解注入到 @Configuration 修饰的类中。
当实例化或者加载 AppConfig 类实例的时候,就会从 app.properties 外部配置当中,找到 bean.name 的配置信息,并把值设置给 beanName。
这种方式经常会与 Spring 的 PropertySourcesPlaceholderConfigurer 搭配使用。
@Import
导入注解。可以通过它来组合两个或者多个被 @Configuration 修饰的类,把多个配置类组合到一起,目的是实现配置的拆分。
类似于 Spring XML 配置方式中的 <import>
标签。
由于 @Configuration 对象,是做为一个 Spring Bean 对象在容器当中被管理的,因此被导入的 @Configuration 对象(配置)也是可以被注入的,比如通过构造器来注入。
DatabaseConfig 做为 AppConfig 的一个变量,通过构造方法注入进来,然后就可以使用 DatabaseConfig 相关的配置信息了。
启动
现在,不管是 AppConfig,还是被导入的 DatabaseConfig 都可以通过注册到 Spring Context 当中来启动。只需要注册 AppConfig 就可以了,因为 DatabaseConfig 已经被包含在 AppConfig 中了。
启动方法:给 Spring Context 注册导入的 @Configuration 类。
@Profile
多环境注解。实际的项目当中,至少分为开发、测试、生产三种环境,每种环境的配置信息,应该都是不一样的,比如数据库、缓存等信息。
@Configuration 所修饰的类还可以被 @Profile 修饰,来指定不同环境信息。
上面的例子分别声明了开发阶段和生产阶段的数据源配置。
在 Spring Bean 的方法层次上,还可以声明一些 @Profile 的条件。
都是叫做 dataSource 的 Spring Bean,配置信息也在同一个 @Configuration 类当中,只是通过 @Profile 的值不同来区分。但是这是一个条件判断,当前环境如果是 development,DataSource Spring Bean 就是 embeddedDatabase,而当前环境如果是 production,DataSource Spring Bean 就是 productionDatabase。
上下两种方式,本质上都是一样的,只是上面的配置方式需要两个 @Configuration 配置类,而下面的方式,一个 @Configuration 配置类就可以了。
@ImportResource
导入配置文件注解。@Configuration 类也可以使用 @ImportResource 注解将 Spring XML 配置文件导入 @Configuration类。
database-config.xml 配置文件中的内容就被导入到 AppConfig 当中了。
用途不是特别大,不过对于老系统的架构迁移来说,也是一种解决方案,比如从 Spring XML 架构迁移到 Spring Boot 架构。
嵌套
@Configuration 类可以相互嵌套。
内层的 DataSource 也会自动注入到外层的 dataSource 当中。
在这种情况下,仅需要针对应用程序上下文注册 AppConfig。由于是嵌套的 @Configuration 类,因此将自动注册 DatabaseConfig。当 AppConfig 和 DatabaseConfig 之间的关系已经很明显的时候,就无需使用 @Import 注解了。
此外,嵌套的 @Configuration 类可以与 @Profile 注解一起搭配使用,为内层的 @Configuration 类提供同一配置 bean 的两个不同选择,比如开发环境和测试环境,相同 bean 的两种选择。
在一个 Spring Boot 的项目中,基本都会存在一个 config 的代码包。里面存放着项目的各种各样配置类,而配置的具体值,很可能放置在外部的 properties 或者 yml 文件中。
延迟加载
默认情况下,在容器启动的时候,被 @Bean 注解修饰的方法会提早实例化。为了避免这种情况,而是用到的时候才初始化。@Configuration 注解可以与 @Lazy 注解搭配使用,用来标识所有的被 @Bean 注解所修饰的方法,在默认情况下都是延迟初始化的。另外 @Lazy 也可以用于单个的 @Bean 方法搭配使用。也就是如果 @Lazy 修饰类,类中所有的 @Bean 方法都是延迟初始化,如果 @Lazy 修饰具体的一个 @Bean 方法,只有这个方法才是延迟初始化。
测试
Spring 测试模块中提供的 Spring TestContext 框架提供了 @ContextConfiguration 注解,它可以接受@Configuration 类对象的数组。
约束
@Configuration 所修饰的类是有几点约束。
@Configuration 必须修饰类。
@Configuration 类必须是非最终类,不能被 final 修饰。
@Configuration 类必须是非本地的(即不得在方法中声明)。
嵌套的 @Configuration 类必须声明为静态,被 static 修饰。
@Bean 方法可能不会创建更多的配置类(任何这样的实例都将被视为常规 Bean,其配置注释保持未被检测到)。
结尾
在 Spring Boot 的开发中,这种 @Configuration 类是一定会出现的。有些配置是使用了某些外部 jar 配置的,还有些配置是根据项目实际需要自定义的。自定义的配置一定要以 @Configuration 这种方式来应用。
Last updated