使用
Spring @Bean是一个方法级别的注解,用于产生一个被Spring IoC容器所管理的Bean。通常情况下,@Bean可以与@Configuration和@Component注解一起使用(@Configuration和@Component是方法级别的注解)。在默认情况下@Bean注解所产生的Bean是单例模式的,此外,@Bean还可以与@Scope,@Lazy,@DependOn和@Primary注解一起使用。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
//name的别名,效果等同于name
@AliasFor("name")
String[] value() default {};
//用于指定Bean的名称
@AliasFor("value")
String[] name() default {};
@Deprecated
Autowire autowire() default Autowire.NO;
//布尔类型,用于限定当前的Bean是否可以自动注入到其他Bean中,默认是true
boolean autowireCandidate() default true;
//在初始化Bean实例时需要调用的方法名称。默认没有要调用的方法
//注意initMethod所指定的方法必须是不带入参的方法,且该方法允许在运行时抛出异常
String initMethod() default "";
//在关闭应用上下文时要在Bean中调用的方法名称,默认不调用任何方法
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
源码
ConfigurationClassParser#doProcessConfigurationClass
中
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
//处理接口中有@Bean注解的,逻辑差不多
processInterfaces(configClass, sourceClass);
检索@Bean修饰的方法,把方法的metadata和类configClass封装成BeanMethod
加入到ConfigurationClass中的beanMethods集合中,这里的作用就是收集@Bean
修饰的方法
要想进行实例化,那必须先转换为BeanDefinition,我们已经把需要处理的@Bean
都收集好了,接下里就是对集合中的进行load操作
this.reader.loadBeanDefinitions(configClasses);
...
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
这里循环遍历每个BeanMethod,交给ConfigurationClassBeanDefinitionReader
处理
//拿到@Bean修饰的方法的类
ConfigurationClass configClass = beanMethod.getConfigurationClass();
//方法的元数据
MethodMetadata metadata = beanMethod.getMetadata();
//方法名
String methodName = metadata.getMethodName();
//拿到注解信息
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);
// 注册别名,@Bean注解的name属性的值
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
//实例化一个BeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
//@Bean修饰的是静态方法,设置beanClass和factoryMethod的值
if (metadata.isStatic()) {
// static @Bean method
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
}
else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
beanDef.setUniqueFactoryMethodName(methodName);
}
//如果@Bean修饰的是非静态方法,设置factoryBean和factoryMethod的值
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
//填充BeanDefinition的属性(@Lazy,@Primary,@Dependson,@Role,@Description)
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
//设置initMethod
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
//设置destroyMethod
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
...
//Scope等属性相关操作
...
//把BeanDefinition注册到注册器中BeanDefinitionRegistry
this.registry.registerBeanDefinition(beanName, beanDefToRegister);