Spring/SpringBoot系列之@Configuration详解【十九】
现在大部分的Spring项目都采用了基于注解的配置,使用@Configuration 标记类作为配置类 替换 xml配置文件。一行简单的注解就可以解决很多事情。但是,其实每一个注解背后都有很多值得学习和思考的内容。比如:@Configuration有什么用?@Configuration和XML有什么区别?哪种好?@Autowired 、 @Inject、@Resource 之间有什么区别?@Val
现在大部分 Spring 项目都采用了基于注解的配置,使用 @Configuration 标记类作为配置类替换 xml 配置文件。一个简单的注解就可以解决很多事情。但是,其实每一个注解背后都有很多值得学习和思考的内容。比如:
- @Configuration有什么用?
- @Autowired 、 @Inject、@Resource 之间有什么区别?
- @Value、@PropertySource 和 @Configuration?
- Spring如何处理带@Configuration @Import的类?
- @Profile有什么用?
- @Configuration 如何嵌套?
- Spring如何对Bean进行延迟初始化?
- Spring项目怎么进行单元测试?
- @Configuration 使用上有哪些约束?
1. @Configuration 基本说明
先看源码:
翻译过来大概意思是:表明一个类中声明一个和多个 @Bean 标记的方法,并且这些方法被 Spring 容器管理用于生成 Bean 定义以及在运行时这些 Bean 的服务请求。
如何启动被 @Configuration 标记的类:
源码注释中有这么一段:
通过注释看到,可以通过使用 AnnotationConfigApplicationContext 来引导启动这个被 @Configuration 注解的类;如果在web项目中,使用 AnnotationContextWebApplicationContext 引导。
下面通过代码进行理解:
-
新建一个 MyConfiguration 配置类:
上述 MyConfiguration 加入 @Configuration 注解,表明这是一个配置类。有一个 myBean() 的方法并用 @Bean 进行注释,返回一个 MyBean 的实例,表明这个方法返回的实例需要被 Spring 进行管理。@Bean 如果不指定名称的话,使用方法名作为实例的名称。 -
创建 MyBean:
-
创建测试类:
输出:
2. 基于 @ComponentScan 扫描获取 Bean 定义
@Configuration 使用 @Component 进行原注解,因此被@Configuration 注解的类也可以被组件扫描到。另外 @Controller, @Service, @Repository, @Component 四个注解标记的类都能够通过 @ComponentScan 扫描到,其中 @Controller,@Service,@Repository 的注解上都有 @Component,这些注解最大的区别就是使用的场景和语义不一样,这里不进行赘述。
下面通过代码进行理解:
- 定义三个类,类上分别用 @Component, @Configuration, @Controller 进行标注:
- 在 MyConfiguration上加上 @ComponentScan 注解,扫描上面5个类所在的包:
- 测试类:
输出:
3. @Configuration 和 Environment
@Configuration 通常和 Environment 一起使用,通过使用 @PropertySource,向 Environment 对象提供属性源。
- 在 resources 目录下新建 beanName.properties 文件:
- 新建一个@Configuration配置类,通过 @PropertySource 引入属性文件,同时注入 Environment 对象:
- 测试:
输出如下:
4. @Autowired 、 @Inject、@Resource 的区别
@Inject: 这是 jsr330 的规范,通过 AutowiredAnnotationBeanPostProcessor 类实现的依赖注入。位于 javax.inject 包内,是Java自带的注解。
@Inject
@Named("environment")
Environment env;
注:如果不加 @Named 注解,需要配置与变量名一致即可。
@Autowired: Spring 提供的注解,通过 AutowiredAnnotationBeanPostProcessor 类实现注入。位于org.springframework.beans.factory.annotation 包内。
@Autowired
Environment env;
注:默认是通过 byType 实现注入
@Resource: @Resource 是 jsr250 规范的实现,通过 CommonAnnotationBeanPostProcessor 类实现注入。@Resource 一般会指定一个name属性,如下:
@Resource(name = "environment")
Environment env;
注:默认是通过 byName 实现注入
区别:
@Autowired 和 @Inject 基本是一样的,因为两者都是使用 AutowiredAnnotationBeanPostProcessor 来处理依赖注入。但是@Resource 是个例外,它使用的是 CommonAnnotationBeanPostProcessor 来处理依赖注入。当然,两者都是 BeanPostProcessor。
5. @Value、@PropertySource 和 @Configuration
@Configuration 可以和 @Value 和 @PropertySource 一起使用读取外部配置文件,具体用法如下:
在config 包下新建一个ReadValueFromPropertySource类,代码如下:
通过 @PropertySource 引入配置文件,使用 @Value 能够获取到属性值。
修改MyBean类,增加一个name属性和一个构造器,再生成其toString() 方法:
在 SpringConfigurationApplication 中进行测试,如下:
输出:
6. @Import 和 @Configuration
详情可以查看这篇文章:Spring/SpringBoot系列之SpringBoot 源码常用注解【九】
7. @Profile
@Profile: 用来实现多环境配置,典型的如数据源。通过激活不同的环境,来进行数据源的切换。
三种激活方式:
- 可以通过 ConfigurableEnvironment.setActiveProfiles() 以编程的方式激活;
- 可以通过 AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME (spring.profiles.active) 属性设置为 JVM 属性
- 通过 @ActiveProfiles 注解在集成测试中以声明方式激活配置文件。
作用域:
- 作为类级别的注解,在任意类或者直接与 @Component 进行关联
- 作为原注解,可以自定义注解
- 作为方法的注解,作用在任何方法
8. @ImportResource 和 @Configuration
@ImportResource: 这个注解提供了与 @Import 功能相似作用,通常与 @Configuration 一起使用,只不过 ImportResource 是针对 xml 配置文件的,为了兼容旧的传统项目进行改造。下面以一个示例来看一下具体用法:
在config下新建 TestService 类,声明一个构造函数:
在 resources 目录下新建 importResources.xml ,为了导入TestService:
新建一个 ImportResourceWithConfiguration,用于读取配置文件:
测试:
输出:
9. @Configuration 嵌套
@Configuration注解作用在类上,就和普通类一样能够进行相互嵌套,定义内部类。
// 来自JavaDoc
@Configuration
public class AppConfig{
@Inject
DataSource dataSource;
@Bean
public MyBean myBean(){
return new MyBean(dataSource);
}
@Configuration
static class DataConfig(){
@Bean
DataSource dataSource(){
return new EmbeddedDatabaseBuilder().build()
}
}
}
在上述代码中,只需要在应用程序的上下文中注册 AppConfig 。由于是嵌套的@Configuration 类,DataConfig 将自动注册。当 AppConfig 、DataConfig 之间的关系已经隐含清楚时,这就避免了使用@Import 注解的需要。
10. @Lazy 延迟初始化
@Lazy : 表明一个bean 是否延迟加载,可以作用在方法上,表示这个方法被延迟加载;可以作用在 @Component (或者由@Component 作为原注解) 注释的类上,表明这个类中所有的 bean 都被延迟加载。除了上面两种作用域,@Lazy 还可以作用在 @Autowired 和 @Inject 注释的属性上,在这种情况下,它将为该字段创建一个惰性代理,作为使用 ObjectFactory 或 Provider 的默认方法。
下面来演示一下:
修改 MyConfiguration 类,在该类上添加 @Lazy 注解,新增一个 IfLazyInit() 方法,检验是否被初始化。
测试类:
输出你会发现没有关于bean的定义信息:
但是当吧@Lazy 注释拿掉,你会发现输出了关于bean的初始化信息:
11. @RunWith 和 @ContextConfiguration
Junit4 测试类,用于注解在类上表示通过 Junit4 进行测试,可以省略编写启动类代码,是 ApplicationContext 等启动类的替换。一般用 @RunWith 和 @Configuration 进行单元测试,这是软件开发过程中非常必要而且具有专业性的一部分:
12. @Enable 启动 Spring 内置功能
详情查阅 @EnableAsync,@EnableScheduling,@EnableTransactionManagement,@EnableAspectJAutoProxy,@EnableWebMvc 官方文档
13. @Configuration 使用约束
- 必须以类的方式提供(即不是从工厂方法返回的实例)
- @Configuration 注解的类必须是非 final 的
- 配置类必须是非本地的
- 任何嵌套的 @Configuration 都必须是 static 的。
更多推荐
所有评论(0)