一、概述
@Bean
属于配置元注解
。其他几个分别为
@Configuration
@Import
@DependsOn
后置处理器 org.springframework.context.annotation.ConfigurationClassPostProcessor
完成配置类解析操作,
与这些注解相配套的是org.springframework.context.annotation.ConfigurationClassPostProcessor
后置处理器。他们负责处理这些与配置相关的注解。
二、@Bean
2.1 @Bean 预览
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
@Deprecated
Autowire autowire() default Autowire.NO;
boolean autowireCandidate() default true;
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
name
为数组类型,可以同时存在多个名称。2.2
@Scope, @Lazy, @DependsOn, @Primary, @Order
@Bean
可与@Scope, @Lazy, @DependsOn, @Primary, @Order
等注解完成特定的单例类配置。2.3
通常,@Configuration
类中的@Bean
方法@bean
方法在@configuration
类中声明。在这种情况下,bean
方法可以通过直接调用引用同一类中的其他@bean
方法,确保单例作用域以及AOP
语义。因为,带有@Configuration
注解的配置类会被CGLib
字节码提升,对内部方法进行动态代理。因此,在这种模式下,不能将@Configuration
的类标记为final
或private
。2.4
@Bean
Lite 模式@Bean
也可以在没有使用@Configuration
注解的类中声明,在这种情况下,@Bean
将会以所谓的lite
模式进行处理,即不进行字节码提升。Lite
模式中的@Bean
方法将会被容器视为普通的工厂方法,并且能正常地应用作用域以及 Spring 相关生命周期回调。但当另一个@Bean
方法调用另一个@Bean
方法时,调用的是标准的 Java 方法,而不是通过 CGLib 代理拦截方法调用,所以会产生不必要的异常。所以,请在配置类中写有@Configuration
注解。2.5 静态方法的 @Bean
对于返回BeanFactoryPostProcessor(BFPP)
类型的@Bean
方法,必须要特别考虑,因为 BFPP 对象必须在容器生命周期早期实例化,因为它会干扰@Configuration
类中的@Autowired
、@Value
、@PostConstruct
等注解的处理。为了避免引起不必要的错误,应该将方法设置为static
。
通过将此方法标记为静态,可以在不引发其声明的@Bean
public static PropertyPlaceholderConfigurer ppc() {
// instantiate, configure and return ppc ...
}
@Configuration
类的实例化的情况下调用它(也就是当前方法脱离当前的配置类),从而避免上述生命周期冲突。但是请注意,静态的@Bean
方法在作用域和 AOP 语义方面不会像上面提到的那样得到增强。这在 BFPP 情况下是可行的,因为其他@bean 方法通常不引用这些方法。作为提醒,将为任何具有可分配给BeanFactoryPostProcessor
的返回类型的非静态@bean 方法发出 warn 级日志消息。2.6 示例
```java public class A { @Override public String toString() {
} }return "A";
@Configuration public class ConfigurationDemo { @Bean public A a() { return new A(); } public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(ConfigurationDemo.class); context.refresh();
System.out.println(context.getBean(A.class));
context.stop();
}
} // OUTPUT // A
<a name="tslVx"></a>
# 三、ConfigurationClassPostProcessor 源码分析
<a name="TUB8V"></a>
## 3.1 Spring 容器后置处理器调用栈
从上图可知,容器执行所有后置处理器是在`org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors(beanFactory)` 方法被调用。而 `ConfigurationClassPostProcessor` 则是用来解析我们的配置类。**<br />在此方法中,最重要的方法是`this.reader.loadBeanDefinitions(ConfigClasses)` ,它的任务是解析配置类,并注册相关的 `BeanDefinition` 。<br /><br />可以通过左下角的调用栈获取解析注解 `@Bean`的完整链路。<br />解析注解 `@Bean` ,就是让他变成 `BeanDefinition`(菜谱),供后续对他进行实例化。解析核心代码如下:
```java
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes");
// Consider name and any aliases
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// Register aliases even when overridden
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// Has this effectively been overridden before (e.g. via XML)?
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
return;
}
// 根据配置元信息创建BeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// @Bean注解在静态方法之上
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
}
else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
beanDef.setUniqueFactoryMethodName(methodName);
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
四、附录
/**
* 基于配置类的注册表构建和验证配置模型
* 任务:解析用户的配置类(@Configuration)
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// #1 获取所有已注册的bean元信息
String[] candidateNames = registry.getBeanDefinitionNames();
// #2 循环遍历,只为找到配置类(Spring的配置类范围很大,不仅仅局限于使用注解@Configuration,也可以是@ComponentScan()、@Import等等)
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
// 2-1 判断是否已经确定当前类类类型
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 2-2 检查给定的bean元信息是否为 配置类(或在配置/组件类中声明的嵌套组件类,也要自动注册)的候选类,并相应地对其进行标记
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 如果是配置类的话,会放到configCandidates集合,将配置类信息使用BeanDefinitionHolder包装并放在configCandiates集合里
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// #3 根据@Order的值进行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// #4 检测通过封闭的应用程序上下文提供的任何自定义bean名称生成策略
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// #5 循环解析Bean元信息Map中的所有配置类。
// 重点注解 @Import、@ComponentScan
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 重点△:5-1 解析候选者
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 5-2 将配置类中的带@Bean的Bean元信息存放到beanDefinitionMap中
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// #6 将ImportRegistry注册为Bean,以支持ImportAware @Configuration类
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// 清除缓存
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}