[Spring6.0源码解析]简述@Configuration注解
Posted 阿宅奋斗史
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Spring6.0源码解析]简述@Configuration注解相关的知识,希望对你有一定的参考价值。
@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容器事,需要注意两点:
- 如果使用传入 Class 入参的构造函数,则传入Class的配置类上的
@Configuration
可以省略,但是如果省略@Configuration
,每次调用配置类中被@Bean
标注的方法时,都会返回不同的 Bean 实例对象。 - 如果使用传入 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
的抽象实现
终于有人把Spring核心源码讲清楚了!
Spring每集成一个开源软件,就需要增加一些基础配置。随着Spring开发大型项目引入多项配置文件,其越来越难理解,并容易配置出错。为解决这个问题,Spring Boot 1.0.0在14年发布。
我们知道在 Spring Boot 中可以用一个 @Configuration 配置文件来配置所有 Bean 及其他配置,但其实没必要这么做。
我们可以把相关的配置独立出来,放到多个 @Configuration 中,如以下参考:
MainConfiguration:项目主要配置
DataSoureceConfiguration:数据源配置
RedisConfiguration:Redis配置
MongoDBConfiguration:MongoDB配置
Spring Boot 现在对原有的 Spring MVC 传统项目是支持的非常好的,不管是 Servlet,还是 XML 配置文件,都可以轻松集成。
那么,如何系统的学习Spring呢?
当你学完课程,可以回过头看看这些题目,自己都掌握了吗?
1)Spring整合MyBatis核心源码处理之"偷梁换柱"
2)Spring注入模型详解以及各注入模型的作用
3)Spring整合MyBaits的时,代理对象在什么时候生成的
4)详解我们Spring容器中的BeanDefinition对象以及存储结构
5)BeanFactoryPostProcessor Vs BeanPostProcessor 组件执行时机以及作用分析
6)Spring整合SpringMvc的,我们的ContextLoadListener的作用和功能分析
7)Spring整合SpringMvc的,我们的DispatcherServlet的作用和分析
8)什么是Spring整合SpringMvc的父子容器以及关系
9)SPI机制服务动态扩展机制详解
10)SpringBoot自动装配原理结合SPI机制如何完成自动装配功能
以上是关于[Spring6.0源码解析]简述@Configuration注解的主要内容,如果未能解决你的问题,请参考以下文章