@Configuration 标注在类上,启动 Spring 会自动扫描@Configuration注解的类,将其注册到IOC容器并实例化bean对象。如果在@Configuration注解的类中使用@Bean注解某个类对象的方法,Spring也会自动将注解了@Bean的方法注册到IOC容器,并进行实例化。

注解源码

@Configuration 注解本质上是个 @Component 注解,所以被 @Configuration 标注的类会被注册到IOC,且可以被 @ComponentScan 注解扫描到。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration { /**
* 存入到Spring IOC容器中的ID
*/
@AliasFor(annotation = Component.class)
String value() default ""; /**
* 表示被@Configuration注解的类是否被代理,以及配置类中被@Bean注解的方法生成的Bean
* 在IOC容器中是否为单例对象
*
* true:full全局模式(默认)
* false:lite轻量级模式
*
* full全局模式,被@Configuration注解的配置类会被代理(CGLIB实现),配置类中被@Bean
* 注解的方法生成的Bean在IOC容器中是单例模式。也就是说,无论调用多少次被@Bean标注的
* 方法,返回的都是同一个bean对象。
*
* lite轻量级模式,被@Configuration注解的配置类不会被代理,配置类中被@Bean注解的方法
* 生成的Bean在IOC容器中也不是单例模式。也就是说,每次调用被@Bean注解标注的方法时,都会
* 返回一个新的Bean对象。
*
* @since 5.2(Spring 5.2版本加入)
*/
boolean proxyBeanMethods() default true; /**
* 表示使用@Bean注解标注的方法是否需要唯一的方法名。
*
* true:使用@Bean注解标注的方法具有唯一方法名称,且方法名称不会重叠
* false:使用@Bean注解标注的方法不唯一,存在重叠风险
*
* 默认为true。
*
* @since 6.0(Spring 6.0版本加入)
*/
boolean enforceUniqueMethods() default true; }

使用场景

当某个类被@Configuration注解标注时,说明这个类是配置类。可以在这个类中,使用@Bean注解,向IOC容器中注入Bean对象;也可以使用 @Autowrite@Resource@Inject等注解来注入所需要的Bean对象。

另外,在使用 AnnotationConfigApplicationContext 类创建IOC容器事,需要注意两点:

  1. 如果使用传入 Class 入参的构造函数,则传入Class的配置类上的 @Configuration 可以省略,但是如果省略 @Configuration ,每次调用配置类中被 @Bean 标注的方法时,都会返回不同的 Bean 实例对象。
  2. 如果使用传入 String 入参的构造函数,表示传入应用程序的包名来创建 IOC容器,则配置类上的 @Configuration 不可以省略。

两种构造方法如下:

	/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given component classes and automatically refreshing the context.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
} /**
* Create a new AnnotationConfigApplicationContext, scanning for components
* in the given packages, registering bean definitions for those components,
* and automatically refreshing the context.
* @param basePackages the packages to scan for component classes
*/
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}

使用案例

准备代码

  • 一个用于注册到IOC的类:
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
  • 配置类
@Configuration
public class ConfigurationAnnotationConfig {
@Bean
public Person person(){
return new Person();
}
}
  • 启动类
public class ConfigurationAnnotationTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationAnnotationTest.class); public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigurationAnnotationConfig.class);
ConfigurationAnnotationConfig config = context.getBean(ConfigurationAnnotationConfig.class);
Person person1 = config.person();
Person person2 = config.person();
LOGGER.info("person1 是否等于 person2 ===>> {}", (person1 == person2));
}
}

proxyBeanMethods的使用

在之前提到,proxyBeanMethods配置表示用 @Bean 注解的方法在IOC容器中是否为单例对象,默认为true。

默认情况下,打印出结果如下:

person1 是否等于 person2 ===>> true

修改一下proxyBeanMethods的值为false:

@Configuration(proxyBeanMethods = false)
public class ConfigurationAnnotationConfig {
@Bean
public Person person(){
return new Person();
}
}

打印结果如下:

person1 是否等于 person2 ===>> false

从输出结果可以看出,当@Configuration中的proxyBeanMethods属性为false时,每次调用@Configuration注解标注类中被@Bean标注的方法时,都会返回不同的Bean实例对象。

创建IOC容器

传入配置类

调用AnnotationConfigApplicationContext类的构造方法传入配置类的Class对象创建IOC容器时,可以省略配置类上的@Configuration注解,如下:

public class ConfigurationAnnotationConfig {
@Bean
public Person person(){
return new Person();
}
}

输出结果:

person1 是否等于 person2 ===>> false

可以看到,若省略配置类上的@Configuration注解,则每次调用配置类中被@Bean注解标注的方法时,都会返回不同的Bean实例对象,与@Configuration中设置proxyBeanMethods的属性为false的效果相同。

传入包

调用AnnotationConfigApplicationContext类的构造方法传入包名创建IOC容器时,不能省略配置类上的@Configuration注解:

public class ConfigurationAnnotationConfig {
@Bean
public Person person(){
return new Person();
}
}

执行函数:

    public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("io.binghe.spring.annotation.chapter01.configuration");
ConfigurationAnnotationConfig config = context.getBean(ConfigurationAnnotationConfig.class);
Person person1 = config.person();
Person person2 = config.person();
LOGGER.info("person1 是否等于 person2 ===>> {}", (person1 == person2));
}

此时运行main方法,会发生报错:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'io.binghe.spring.annotation.chapter01.configuration.config.ConfigurationAnnotationConfig' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1148)
at io.binghe.spring.annotation.chapter01.configuration.ConfigurationAnnotationTest.main(ConfigurationAnnotationTest.java:36)

添加上@Configuration注解则程序执行正常。

扩展知识

AnnotationConfigApplicationContext

Spring在 BeanFactory 的基础上提供一些具体容器的实现。AnnotationConfigApplicationContext就是一个用来管理注解 Bean 的容器。如下结构图:

从图中可以看到,AnnotationConfigApplicationContext继承GenericApplicationContext(通用应用上下文),而GenericApplicationContext又实现了BeanDefinitionRegistry接口,所以可以通过AnnotationConfigApplicationContext实例类注册BeanDefintion,然后调用refresh()方法来初始化上下文。AnnotationConfigApplicationContext还继承了AbstractApplicationContext,而AbstractApplicationContext提供了ApplicationContext的抽象实现

[Spring6.0源码解析]简述@Configuration注解的更多相关文章

  1. Android事件总线(二)EventBus3.0源码解析

    1.构造函数 当我们要调用EventBus的功能时,比如注册或者发送事件,总会调用EventBus.getDefault()来获取EventBus实例: public static EventBus ...

  2. solr&lucene3.6.0源码解析(四)

    本文要描述的是solr的查询插件,该查询插件目的用于生成Lucene的查询Query,类似于查询条件表达式,与solr查询插件相关UML类图如下: 如果我们强行将上面的类图纳入某种设计模式语言的话,本 ...

  3. solr&lucene3.6.0源码解析(三)

    solr索引操作(包括新增 更新 删除 提交 合并等)相关UML图如下 从上面的类图我们可以发现,其中体现了工厂方法模式及责任链模式的运用 UpdateRequestProcessor相当于责任链模式 ...

  4. Heritrix 3.1.0 源码解析(三十七)

    今天有兴趣重新看了一下heritrix3.1.0系统里面的线程池源码,heritrix系统没有采用java的cocurrency包里面的并发框架,而是采用了线程组ThreadGroup类来实现线程池的 ...

  5. solr&lucene3.6.0源码解析(二)

    上文描述了solr3.6.0怎么采用maven管理的方式在eclipse中搭建开发环境,在solr中,为了提高搜索性能,采用了缓存机制,这里描述的是LRU缓存,这里用到了 LinkedHashMap类 ...

  6. solr&lucene3.6.0源码解析(一)

      本文作为系列的第一篇,主要描述的是solr3.6.0开发环境的搭建   首先我们需要从官方网站下载solr的相关文件,下载地址为http://archive.apache.org/dist/luc ...

  7. apache mina2.0源码解析(一)

    apache mina是一个基于java nio的网络通信框架,为TCP UDP ARP等协议提供了一致的编程模型:其源码结构展示了优秀的设计案例,可以为我们的编程事业提供参考. 依照惯例,首先搭建a ...

  8. EventBus3.0源码解析

    本文主要介绍EventBus3.0的源码 EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递. EventBus使用简单,并将事件发布和订阅充 ...

  9. Retrofit2.0源码解析

    欢迎访问我的个人博客 ,原文链接:http://wensibo.net/2017/09/05/retrofit/ ,未经允许不得转载! 今天是九月的第四天了,学校也正式开学,趁着大学最后一年的这大好时 ...

  10. DataX 3.0 源码解析一

    源码解析 基本调用类分析 任务启动由python脚本新建进程进行任务执行,后续执行由Java进行,以下将对java部分进行分 其中的调用原理机制. Engine 首先入口类为com.alibaba.d ...

随机推荐

  1. C#设计模式09——组合模式的写法

    1. 什么是C#组合模式? 组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示"整体/部分"层次结构.使用此模式,客户端可以按相同的方式处理单个对象和对象集合,而不必关 ...

  2. 如何让Dec-C++支持C++11

    1.问题 Dev-C++默认设置中是不支持C++11版本特性的,如Lambda表达式,nullptr等均不提供支持 2.解决 设置编译选项 编译时加上命令-std==c++11即可

  3. 【SHELL】在指定格式的文件中查找字符串

    在指定格式的文件中查找字符串 grep -nr "string" --include=*.{c,cpp,h} 在排除指定格式的文件中查找字符串 grep -nr "str ...

  4. python环境 anaconda安装

    官网: https://www.anaconda.com/distribution/#macos 国内镜像: https://mirrors.tuna.tsinghua.edu.cn/anaconda ...

  5. [转帖]深入浅出分析LSM树(日志结构合并树)

    https://zhuanlan.zhihu.com/p/415799237 ​ 目录 收起 零.前言 一.LSM树数据结构定义 二.插入操作 三.删除操作 四.修改操作 五.查询操作 六.合并操作 ...

  6. [转帖]TiDB升级、TiFlash测试及对比ClickHouse

    原创 NewSQL 作者:o烟雨潇潇o 时间:2020-05-13 11:53:16  4418  0 TiDB升级.TiFlash测试及对比ClickHouse                   ...

  7. [转帖]线上Java 高CPU占用、高内存占用排查思路

    一.前言 处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题.当然,这些问题的最终导致的直观现象就是系统运行缓慢,并且有大量的报警.本文主要针对系统 ...

  8. 【分享代码片段】terraform中,如何从刚刚创建的 deployment 中获得所有容器的名字和 ip

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 不好意思,刚刚才开始用 terraform,或许是更好的办 ...

  9. 【发现一个问题】VictoriaMetrics中,所有vmstorage在中午12:00切换索引,导致所有vm-insert发生oom

    请看我提的issue: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2464 bug: vm v1.70.0, all vmst ...

  10. vue基础系列文章12---创建脚手架

    一.交互式命令行创建 1.运行 vue create myvue 选择默认创建模式,会在指定的文件夹下创建文件 2.进入到myvue文件夹,运行:npm  run serve 3.访问本地的地址就可以 ...