@Configuration
標(biāo)注在類上,啟動(dòng) Spring 會(huì)自動(dòng)掃描@Configuration
注解的類,將其注冊(cè)到IOC容器并實(shí)例化bean對(duì)象。如果在@Configuration
注解的類中使用@Bean
注解某個(gè)類對(duì)象的方法,Spring也會(huì)自動(dòng)將注解了@Bean
的方法注冊(cè)到IOC容器,并進(jìn)行實(shí)例化。
注解源碼
@Configuration
注解本質(zhì)上是個(gè) @Component
注解,所以被 @Configuration
標(biāo)注的類會(huì)被注冊(cè)到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容器中是否為單例對(duì)象
*
* true:full全局模式(默認(rèn))
* false:lite輕量級(jí)模式
*
* full全局模式,被@Configuration注解的配置類會(huì)被代理(CGLIB實(shí)現(xiàn)),配置類中被@Bean
* 注解的方法生成的Bean在IOC容器中是單例模式。也就是說,無論調(diào)用多少次被@Bean標(biāo)注的
* 方法,返回的都是同一個(gè)bean對(duì)象。
*
* lite輕量級(jí)模式,被@Configuration注解的配置類不會(huì)被代理,配置類中被@Bean注解的方法
* 生成的Bean在IOC容器中也不是單例模式。也就是說,每次調(diào)用被@Bean注解標(biāo)注的方法時(shí),都會(huì)
* 返回一個(gè)新的Bean對(duì)象。
*
* @since 5.2(Spring 5.2版本加入)
*/
boolean proxyBeanMethods() default true;
/**
* 表示使用@Bean注解標(biāo)注的方法是否需要唯一的方法名。
*
* true:使用@Bean注解標(biāo)注的方法具有唯一方法名稱,且方法名稱不會(huì)重疊
* false:使用@Bean注解標(biāo)注的方法不唯一,存在重疊風(fēng)險(xiǎn)
*
* 默認(rèn)為true。
*
* @since 6.0(Spring 6.0版本加入)
*/
boolean enforceUniqueMethods() default true;
}
使用場(chǎng)景
當(dāng)某個(gè)類被@Configuration
注解標(biāo)注時(shí),說明這個(gè)類是配置類。可以在這個(gè)類中,使用@Bean
注解,向IOC容器中注入Bean對(duì)象;也可以使用 @Autowrite
、@Resource
、@Inject
等注解來注入所需要的Bean對(duì)象。
另外,在使用 AnnotationConfigApplicationContext
類創(chuàng)建IOC容器事,需要注意兩點(diǎn):
- 如果使用傳入 Class 入?yún)⒌臉?gòu)造函數(shù),則傳入Class的配置類上的
@Configuration
可以省略,但是如果省略@Configuration
,每次調(diào)用配置類中被@Bean
標(biāo)注的方法時(shí),都會(huì)返回不同的 Bean 實(shí)例對(duì)象。 - 如果使用傳入 String 入?yún)⒌臉?gòu)造函數(shù),表示傳入應(yīng)用程序的包名來創(chuàng)建 IOC容器,則配置類上的
@Configuration
不可以省略。
兩種構(gòu)造方法如下:
/**
* 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();
}
使用案例
準(zhǔn)備代碼
- 一個(gè)用于注冊(cè)到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();
}
}
- 啟動(dòng)類
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容器中是否為單例對(duì)象,默認(rèn)為true。
默認(rèn)情況下,打印出結(jié)果如下:
person1 是否等于 person2 ===>> true
修改一下proxyBeanMethods的值為false:
@Configuration(proxyBeanMethods = false)
public class ConfigurationAnnotationConfig {
@Bean
public Person person(){
return new Person();
}
}
打印結(jié)果如下:
person1 是否等于 person2 ===>> false
從輸出結(jié)果可以看出,當(dāng)@Configuration
中的proxyBeanMethods
屬性為false時(shí),每次調(diào)用@Configuration
注解標(biāo)注類中被@Bean標(biāo)注的方法時(shí),都會(huì)返回不同的Bean實(shí)例對(duì)象。
創(chuàng)建IOC容器
傳入配置類
調(diào)用AnnotationConfigApplicationContext
類的構(gòu)造方法傳入配置類的Class對(duì)象創(chuàng)建IOC容器時(shí),可以省略配置類上的@Configuration
注解,如下:
public class ConfigurationAnnotationConfig {
@Bean
public Person person(){
return new Person();
}
}
輸出結(jié)果:
person1 是否等于 person2 ===>> false
可以看到,若省略配置類上的@Configuration
注解,則每次調(diào)用配置類中被@Bean注解標(biāo)注的方法時(shí),都會(huì)返回不同的Bean實(shí)例對(duì)象,與@Configuration中設(shè)置proxyBeanMethods
的屬性為false的效果相同。
傳入包
調(diào)用AnnotationConfigApplicationContext
類的構(gòu)造方法傳入包名創(chuàng)建IOC容器時(shí),不能省略配置類上的@Configuration
注解:
public class ConfigurationAnnotationConfig {
@Bean
public Person person(){
return new Person();
}
}
執(zhí)行函數(shù):
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));
}
此時(shí)運(yùn)行main方法,會(huì)發(fā)生報(bào)錯(cuò):
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
注解則程序執(zhí)行正常。
擴(kuò)展知識(shí)
AnnotationConfigApplicationContext
Spring在 BeanFactory
的基礎(chǔ)上提供一些具體容器的實(shí)現(xiàn)。AnnotationConfigApplicationContext
就是一個(gè)用來管理注解 Bean 的容器。如下結(jié)構(gòu)圖:文章來源:http://www.zghlxwxcb.cn/news/detail-410037.html
從圖中可以看到,AnnotationConfigApplicationContext
繼承GenericApplicationContext
(通用應(yīng)用上下文),而GenericApplicationContext
又實(shí)現(xiàn)了BeanDefinitionRegistry
接口,所以可以通過AnnotationConfigApplicationContext
實(shí)例類注冊(cè)BeanDefintion
,然后調(diào)用refresh()
方法來初始化上下文。AnnotationConfigApplicationContext
還繼承了AbstractApplicationContext
,而AbstractApplicationContext
提供了ApplicationContext
的抽象實(shí)現(xiàn)文章來源地址http://www.zghlxwxcb.cn/news/detail-410037.html
到了這里,關(guān)于[Spring6.0源碼解析]簡(jiǎn)述@Configuration注解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!