Spring/SpringBoot系列之@Configuration详解【十九】

现在大部分 Spring 项目都采用了基于注解的配置,使用 @Configuration 标记类作为配置类替换 xml 配置文件。一个简单的注解就可以解决很多事情。但是,其实每一个注解背后都有很多值得学习和思考的内容。比如:

  1. @Configuration有什么用?
  2. @Autowired 、 @Inject、@Resource 之间有什么区别?
  3. @Value、@PropertySource 和 @Configuration?
  4. Spring如何处理带@Configuration @Import的类?
  5. @Profile有什么用?
  6. @Configuration 如何嵌套?
  7. Spring如何对Bean进行延迟初始化?
  8. Spring项目怎么进行单元测试?
  9. @Configuration 使用上有哪些约束?

1. @Configuration 基本说明

先看源码:
Spring/SpringBoot系列之@Configuration详解【十九】_第1张图片
Spring/SpringBoot系列之@Configuration详解【十九】_第2张图片
翻译过来大概意思是:表明一个类中声明一个和多个 @Bean 标记的方法,并且这些方法被 Spring 容器管理用于生成 Bean 定义以及在运行时这些 Bean 的服务请求。

如何启动被 @Configuration 标记的类:

源码注释中有这么一段:
Spring/SpringBoot系列之@Configuration详解【十九】_第3张图片
通过注释看到,可以通过使用 AnnotationConfigApplicationContext 来引导启动这个被 @Configuration 注解的类;如果在web项目中,使用 AnnotationContextWebApplicationContext 引导。

下面通过代码进行理解:

  1. 新建一个 MyConfiguration 配置类:
    Spring/SpringBoot系列之@Configuration详解【十九】_第4张图片
    上述 MyConfiguration 加入 @Configuration 注解,表明这是一个配置类。有一个 myBean() 的方法并用 @Bean 进行注释,返回一个 MyBean 的实例,表明这个方法返回的实例需要被 Spring 进行管理。@Bean 如果不指定名称的话,使用方法名作为实例的名称。

  2. 创建 MyBean:
    Spring/SpringBoot系列之@Configuration详解【十九】_第5张图片

  3. 创建测试类:
    Spring/SpringBoot系列之@Configuration详解【十九】_第6张图片
    输出:
    Spring/SpringBoot系列之@Configuration详解【十九】_第7张图片

2. 基于 @ComponentScan 扫描获取 Bean 定义

@Configuration 使用 @Component 进行原注解,因此被@Configuration 注解的类也可以被组件扫描到。另外 @Controller, @Service, @Repository, @Component 四个注解标记的类都能够通过 @ComponentScan 扫描到,其中 @Controller,@Service,@Repository 的注解上都有 @Component,这些注解最大的区别就是使用的场景和语义不一样,这里不进行赘述。

下面通过代码进行理解:

  1. 定义三个类,类上分别用 @Component, @Configuration, @Controller 进行标注:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 在 MyConfiguration上加上 @ComponentScan 注解,扫描上面5个类所在的包:
    Spring/SpringBoot系列之@Configuration详解【十九】_第8张图片
  3. 测试类:
    Spring/SpringBoot系列之@Configuration详解【十九】_第9张图片
    输出:
    Spring/SpringBoot系列之@Configuration详解【十九】_第10张图片

3. @Configuration 和 Environment

@Configuration 通常和 Environment 一起使用,通过使用 @PropertySource,向 Environment 对象提供属性源。

  1. 在 resources 目录下新建 beanName.properties 文件:
    Spring/SpringBoot系列之@Configuration详解【十九】_第11张图片
  2. 新建一个@Configuration配置类,通过 @PropertySource 引入属性文件,同时注入 Environment 对象:
    Spring/SpringBoot系列之@Configuration详解【十九】_第12张图片
  3. 测试:
    Spring/SpringBoot系列之@Configuration详解【十九】_第13张图片
    输出如下:
    Spring/SpringBoot系列之@Configuration详解【十九】_第14张图片

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类,代码如下:
Spring/SpringBoot系列之@Configuration详解【十九】_第15张图片

通过 @PropertySource 引入配置文件,使用 @Value 能够获取到属性值。

修改MyBean类,增加一个name属性和一个构造器,再生成其toString() 方法:
Spring/SpringBoot系列之@Configuration详解【十九】_第16张图片
在 SpringConfigurationApplication 中进行测试,如下:
Spring/SpringBoot系列之@Configuration详解【十九】_第17张图片
输出:
在这里插入图片描述

6. @Import 和 @Configuration

详情可以查看这篇文章:Spring/SpringBoot系列之SpringBoot 源码常用注解【九】

7. @Profile

@Profile: 用来实现多环境配置,典型的如数据源。通过激活不同的环境,来进行数据源的切换。

三种激活方式:

  1. 可以通过 ConfigurableEnvironment.setActiveProfiles() 以编程的方式激活;
  2. 可以通过 AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME (spring.profiles.active) 属性设置为 JVM 属性
  3. 通过 @ActiveProfiles 注解在集成测试中以声明方式激活配置文件。

作用域:

  1. 作为类级别的注解,在任意类或者直接与 @Component 进行关联
  2. 作为原注解,可以自定义注解
  3. 作为方法的注解,作用在任何方法

Spring/SpringBoot系列之@Configuration详解【十九】_第18张图片

8. @ImportResource 和 @Configuration

@ImportResource: 这个注解提供了与 @Import 功能相似作用,通常与 @Configuration 一起使用,只不过 ImportResource 是针对 xml 配置文件的,为了兼容旧的传统项目进行改造。下面以一个示例来看一下具体用法:

在config下新建 TestService 类,声明一个构造函数:
Spring/SpringBoot系列之@Configuration详解【十九】_第19张图片
Spring/SpringBoot系列之@Configuration详解【十九】_第20张图片
在 resources 目录下新建 importResources.xml ,为了导入TestService:
Spring/SpringBoot系列之@Configuration详解【十九】_第21张图片
新建一个 ImportResourceWithConfiguration,用于读取配置文件:
Spring/SpringBoot系列之@Configuration详解【十九】_第22张图片
测试:
Spring/SpringBoot系列之@Configuration详解【十九】_第23张图片
输出:
在这里插入图片描述

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() 方法,检验是否被初始化。
Spring/SpringBoot系列之@Configuration详解【十九】_第24张图片
测试类:
Spring/SpringBoot系列之@Configuration详解【十九】_第25张图片
输出你会发现没有关于bean的定义信息:
Spring/SpringBoot系列之@Configuration详解【十九】_第26张图片
但是当吧@Lazy 注释拿掉,你会发现输出了关于bean的初始化信息:
Spring/SpringBoot系列之@Configuration详解【十九】_第27张图片

11. @RunWith 和 @ContextConfiguration

Junit4 测试类,用于注解在类上表示通过 Junit4 进行测试,可以省略编写启动类代码,是 ApplicationContext 等启动类的替换。一般用 @RunWith 和 @Configuration 进行单元测试,这是软件开发过程中非常必要而且具有专业性的一部分:
Spring/SpringBoot系列之@Configuration详解【十九】_第28张图片
Spring/SpringBoot系列之@Configuration详解【十九】_第29张图片

12. @Enable 启动 Spring 内置功能

详情查阅 @EnableAsync,@EnableScheduling,@EnableTransactionManagement,@EnableAspectJAutoProxy,@EnableWebMvc 官方文档

13. @Configuration 使用约束

  1. 必须以类的方式提供(即不是从工厂方法返回的实例)
  2. @Configuration 注解的类必须是非 final 的
  3. 配置类必须是非本地的
  4. 任何嵌套的 @Configuration 都必须是 static 的。

你可能感兴趣的:(java,spring,spring,boot)