文章目录
Spring IOC容器管理着一个或多个bean。这些bean是使用用户提供给容器的配置元数据创建的,例如XML配置、@Bean注解等方式。
在容器本身内,这些bean定义表示为BeanDefinition 对象。
BeanDefiniton——Bean的元信息
BeanDefinition的注册
- XML配置元信息:
<bean>
标签 - Java注解配置元信息:@Bean、@Component、@Import
- Java API配置元信息:
- BeanDefinitionRegistry.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
- BeanDefinitionReaderUtils.registerWithGeneratedName(AbstractBeanDefinition definition, BeanDefinitionRegistry registry)
- AnnotatedBeanDefinitionReader.registerBean(Class<?> annotatedClass) - 将外部对象注册为Bean:SingletonBeanRegistry.registerSingleton(String beanName, Object singletonObject)
注解方式注册BeanDefinition源码分析
我们从BeanDefinition中也可以看出,这个接口的主要作用更多的是描述一个Bean,就像最开始我们通过XML配置一个Bean一样,Bean的全类名、名称、作用域、是否依赖注入,是否延迟加载等等属性,都在BeanDefinition中可以找到与之对应的属性,因此我们就可以推断,其实我们配置的Bean信息就保存在一个BeanDefinition对象之中。
由于现在企业开发中,大多使用的是注解@Bean的形式来构建对象,因此我选择AnnotationConfigWebApplicationContext类来分析,BeanDefinition是如何创建并生成Bean对象的。
我们找到容器启动的过程中处理BeanDefinition的代码AbstractApplicationContext.refresh()方法(容器启动过程请参考我的这一篇关于容器的文章Spring与IOC容器)
// AbstractApplicationContext.refresh()方法中的这一行就是创建BeanDefinition的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化BeanFactory,并进行xml读取或注解扫描,并将得到的BeanFactory记录在当前实体的属性中
refreshBeanFactory();
//返回当前实体的beanFactory属性
return getBeanFactory();
}
我们发现关键的refreshBeanFactory()方法在AbstractApplicationContext类中是一个抽象方法,需要子类去进行实现,然后我我们点到它的实现类AbstractRefreshableApplicationContext中,看具体的实现逻辑:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建DefaultListableBeanFactory实例,因为它是容器的基础,必须要先被实例化
DefaultListableBeanFactory beanFactory = createBeanFactory();
//为了序列化指定id,如有需要,使得这个BeanFactory从id反序列化到BeanFactory对象
beanFactory.setSerializationId(getId());
//定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象、是否允许bean之间存在循环依赖
customizeBeanFactory(beanFactory);
//初始化DocumentReader,并进行XML文件或注解的读取及解析
loadBeanDefinitions(beanFactory);
//使用全局变量beanFactory记录DefaultListableBeanFactory实例
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
从翻译的注释中,我们知道要看的是loadBeanDefinitions()这个方法,由于它又是一个抽象的方法,而且我们这里要分析注解的实现,所以我就选择了AnnotationConfigWebApplicationContext这个类的实现
进入loadBeanDefinitions()方法的前两行,就得到了两个对象,分别是处理@Bean和XML的<bean>
标签
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
我们这里只看AnnotatedBeanDefinitionReader的register()方法,一路从调用链点到doRegisterBean()方法
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 先声明一个AnnotatedGenericBeanDefinition对象,用于后面进行注册
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
// 校验是否需要注册这个bean,如果没有被@Conditional注解修饰,直接返回false
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 生成bean的名字
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 设置BeanDefinition的lazy、primary、dependsOn、role、description属性
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// BeanDefinitionHolder就是一个BeanDefinition的持有者,持有BeanDefinition的名字和引用
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
// 为提供的目标bean生成一个作用域代理
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 注册给定的definition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
具体的注册逻辑registerBeanDefinition()很简单,由于AnnotationConfigApplicationContext持有的BeanDefinitionRegistry对象是DefaultListableBeanFactory,因此就看它的registerBeanDefinition()实现即可,内部逻辑也比较简单,主要就是看这个BeanDefinition是否有注册过,然后放入BeanFactory维护的一个ConcurrentHashMap,以供后续使用。
BeanDefinition的命名
DefaultBeanNameGenerator
由Spring Framework 2.0.3引入,是BeanNameGenerator的默认实现。
关于XML的解析,请根据个人兴趣看一下AbstractXmlApplicationContext.loadBeanDefinitions()方法,然后从XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource)方法看注册BeanDefinitionBeanDefinition的逻辑,从DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)方法看具体从XML中解析标签注册的逻辑
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 校验root节点的namespaceURI 不为空 且为 http://www.springframework.org/schema/beans
if (delegate.isDefaultNamespace(root)) {
// 获取所有的子节点
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 解析默认标签--<import>、<alias>、<bean>、<beans>
parseDefaultElement(ele, delegate);
} else {
// 解析自定义标签(<aop:config>并不是默认的Namespace,因此Aop在此解析)
delegate.parseCustomElement(ele);
}
}
}
} else {
// 解析自定义标签
delegate.parseCustomElement(root);
}
}
// 解析默认标签方法逻辑
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//对<import>进行解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//对<alias>进行解析
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//对<bean>进行解析
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//对<beans>进行解析
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
AnnotationBeanNameGenerator
由Spring Framework 2.5引入,基于注解扫描的BeanNameGenerator实现。
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
// 如果是基于注解的BeanDefinition
if (definition instanceof AnnotatedBeanDefinition) {
// 根据注解中的BeanName决定bean名称
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// 如果注解中没有给定BeanDefinition的名称,生成一个默认的唯一BeanName
return buildDefaultBeanName(definition, registry);
}
// 通过注解的方式生成BeanDefinition名称
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
AnnotationMetadata amd = annotatedDef.getMetadata();
Set<String> types = amd.getAnnotationTypes();
String beanName = null;
for (String type : types) {
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
// 如果注解类型是@Component、@ManagedBean、@Named,并且注解中包含value属性
if (attributes != null && isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
if (StringUtils.hasLength(strVal)) {
// 校验多个注解修饰一个Bean,却有不同Bean名称的情况
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
return beanName;
}
// 没有通过注解指定名称,生成唯一的BeanDefinition名称
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
// 将一个字符串的首字母大写转为小写,若是"URL"这种字符串,连续多个大写字母开头的,则保持不变
return Introspector.decapitalize(shortClassName);
}
public static String getShortName(String className) {
// 如果是一个内部类的Bean,传入的className为com.durp.study.OutterClass$InnerClass
Assert.hasLength(className, "Class name must not be empty");
int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
// 判断是否是CGLIB的Bean的处理逻辑
int nameEndIndex = className.indexOf(CGLIB_CLASS_SEPARATOR);
if (nameEndIndex == -1) {
nameEndIndex = className.length();
}
String shortName = className.substring(lastDotIndex + 1, nameEndIndex);
// 将$替换为.
// 最终输出为OutterClass.InnerClass
shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR);
return shortName;
}