新闻资讯
Spring Boot(1):核心注解——Bean的加载与配置
一、@SpringBootApplication
这个注解其实是下面三个注解的缩写:
- @EnableAutoConfiguration
- @ComponentScan
- @SpringBootConfiguration
它用于标记main方法所在的类:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
} 复制代码
二、@EnableAutoConfiguration
这个注解开启全局的自动配置,标上这个注解后,Spring Boot会处理jar包下面的META-INF/spring.factories文件,这个文件中的内容可能如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration 复制代码
可以看出,这个文件中指定了哪些配置类应该被自动加载。
三、@SpringBootConfiguration
这个注解与@Configuration注解的作用是一样的,它用于把一个类标记为Spring Boot的配置类。
四、@EnableAutoConfiguration
如果我们不想使用@EnableAutoConfiguration启用全局的自动配置,有时候我们只想使用其中的一部分配置,那么使用注解@ImportAutoConfiguration可以导入给定的配置类:
@ComponentScan("path.to.your.controllers") @ImportAutoConfiguration({WebMvcAutoConfiguration.class
,DispatcherServletAutoConfiguration.class
,EmbeddedServletContainerAutoConfiguration.class
,ServerPropertiesAutoConfiguration.class
,HttpMessageConvertersAutoConfiguration.class}) public class App { public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
} 复制代码
五、指定配置的加载顺序
如果我们的配置需要依赖其它的配置,那么可以使用下面三个注解用于指定配置的加载顺序:
- @AutoConfigureBefore,表示在某个Bean加载之前进行加载;
- @AutoConfigureAfter,表示在某个Bean加载之后进行加载;
- @AutoConfigureOrder,这个注解可以接受一个整数,用于明确的指定加载顺序,它与@Order具有相同的语义。
示例:使用@AutoConfigureAfter
@Configuration @AutoConfigureAfter(CacheAutoConfiguration.class) @ConditionalOnBean(CacheManager.class) @ConditionalOnClass(CacheStatisticsProvider.class) public class RedissonCacheStatisticsAutoConfiguration { @Bean public RedissonCacheStatisticsProvider redissonCacheStatisticsProvider(){ return new RedissonCacheStatisticsProvider();
}
} 复制代码
在上面的代码中,只有在CacheAutoConfiguration加载完成后才会加载RedissonCacheStatisticsAutoConfiguration。
六、Bean的条件加载与配置
Spring Boot的自动配置功能主要通过加载被@Configuration注解的配置类来实现。为了提供更高的扩展性,因此Spring Boot中提供了一系列的@Conditional注解用于约束配置的加载时机。
6.1 根据Bean的存在性加载配置
- @ConditionalOnBean,当所指定的Bean在Spring容器中存在时,则加载对应的配置;
- @ConditionalOnMissingBean,当所指定的Bean在Spring容器中不存在时,则加载对应的配置。
它们可以接受一个Bean的名称或者Class作为参数。
示例:使用@ConditionalOnMissingBean
@Configuration public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean public MyService myService() { ... }
} 复制代码
在上面的代码中,当Spring容器中不存在MyService类型的Bean时才会将其注入。
6.2 根据Class的存在性加载配置
- @ConditionalOnClass,当所指定的类存在时才加载对应配置;
- @ConditionalMissingClass,当所指定的类不存在时才加载对应配置。
它们可以接受一个Class或者字符串类型的类路径作为参数。
示例:使用@ConditionalOnClass
@Configuration // Some conditions public class MyAutoConfiguration { // Auto-configured beans @Configuration @ConditionalOnClass(EmbeddedAcmeService.class) static class EmbeddedConfiguration { @Bean @ConditionalOnMissingBean public EmbeddedAcmeService embeddedAcmeService() { ... }
}
} 复制代码
在上面的代码中,只有当类EmbeddedAcmeService存在,而且它在Spring容器中不存在时才会加载它。
需要注意的是,由于Spring使用ASM进行动态加载,所以就算这两个注解指定了一个在程序运行时不存在的类型它们也能正常工作。
但是,在下面三个条件同时出现时,JVM将会抛出一个ClassNotFoundException异常:
- @Bean、@ConditionalOnClass或@ConditionalMissingClass注解在同一个方法上;
- @Bean所注解的方法返回类型与@ConditionalOnClass或@ConditionalMissingClass注解中所指定的是同一类型;
- 在运行时,这个类型在classpath中不存在。
6.3 根据是不是Web应用加载配置
- @ConditionalOnNotWebApplication,当前应用不是Web应用才会加载对应配置;
- @ConditionalOnWebApplication,当前应用是Web应用才会加载对应配置。
Spring Boot认定一个应用是Web应用,需要下面三个条件中至少有一个成立:
- 使用的上下文是WebApplicationContext;
- 有一个Bean具有session作用域;
- 存在StandardServletEnvironment。
6.4 根据Property加载配置
注解@ConditionalOnProperty可以检测Spring环境变量的值,只有条件成立时才会加载配置。
示例:使用@ConditionalOnProperty
@Configuration public class DataSourceConfiguration { @Bean @ConditionalOnProperty(name = "env", havingValue = "local") DataSource localDataSource() { // ... } @Bean @ConditionalOnProperty(name = "env", havingValue = "prod") DataSource prodDataSource() { // ... }
} 复制代码
上面这段代码演示了DataSource的动态加载,它会通过检测application.properties文件中env选项的值动态加载一个DataSource到Spring容器中。
6.5 根据资源的存在性加载配置
注解@ConditionalOnResource可以根据所指定的资源是否存在来加载相应配置。
示例:使用@ConditionalOnResource
@Configuration public class VendorConfiguration { @ConditionalOnResource(resources = "classpath:vendor.properties") Properties additionalProperties() { // 对vendor.properties进行一些处理 // ... }
} 复制代码
在上面的代码中只有当文件classpath:vendor.properties存在时才会对它进行处理。
6.6 根据SpEL表达式加载配置
注解@ConditionalOnExpression可以检测SpEL表达式的结果,只有表达式的值为真时才会加载相应配置。
示例:使用@ConditionalOnExpression替换@ConditionalOnProperty
@Configuration public class DataSourceConfiguration { @Bean @ConditionalOnExpression("${env} && ${havingValue == 'local'}") DataSource localDataSource() { // ... } @Bean @ConditionalOnExpression("${env} && ${havingValue == 'prod'}") DataSource prodDataSource() { // ... }
} 复制代码
上面这段代码使用@ConditionalOnExpression替换了@ConditionalOnProperty,这样也能实现DataSource的动态加载。
6.7 根据所在云平台进行加载配置
注解@ConditionalOnCloudPlatform能够检测承载Spring Boot应用的云平台,当应用运行在所指定的云平台上面时才会加载对应的配置,这个注解支持下面这些常用的云平台:
- Cloud Foundry
- Heroku
- Kubernetes
- SAP
示例:使用@ConditionalOnCloudPlatform
@Configuration @ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES) public class CloudConfigurationExample { @Bean public MyBean myBean(MyProperties properties) { return new MyBean(properties.getParam);
}
} 复制代码
在上面的代码中,只有当我们的Spring Boot程序运行在K8S平台上面时才会加载MyBean到Spring容器中。
另外,枚举CloudPlatform中存在四个枚举值:
- CLOUD_FOUNDRY
- HEROKU
- KUBERNETES
- SAP
参考资料:
回复列表