您的位置:首页 > 编程语言 > Java开发

Spring Boot【原理分析】(3)——BeanDefinition

2016-12-16 13:24 549 查看

一、简介

BeanDefinition描述了一个Bean的实例,包括属性,构造方法参数,注解等更多信息。为后面实例化Bean提供元数据依据。

BeanDefinition的实现类有:

1. RootBeanDefinition:spring BeanFactory运行期里,内部特殊bean的定义。

2. ConfigurationClassBeanDefinition:继承RootBeanDefinition,ConfigurationClassBeanDefinitionReader内部静态类。上文(2)中提到的Configuration Class内定义的Bean被解析成这个BeanDefinition。

3. ChildBeanDefinition:Spring2.5后弃用。

4. GenericBeanDefinition:@EnableConfigurationProperties和Spring显示创建。@ImportResource

5. ScannedGenericBeanDefinition:上文(2)中提到的ComponentScanAnnotationParser扫描的@Component定义被解析成这个BeanDefinition。

6. AnnotatedGenericBeanDefinition:Spring Boot autoconfigure功能spring.facotries中定义的EnableAutoConfiguration,以及内部子Configuration。@Import

二、创建过程

1.GenericBeanDefinition:

这里主要看一下@ImportResource xml中定义的bean。

ConfigurationClassBeanDefinitionReader解析Configuration Class时会解析ImportResource,XmlBeanDefinitionReader具体解析xml中的Beans,最终由BeanDefinitionParserDelegate解析每个Bean:

public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {

this.parseState.push(new BeanEntry(beanName));

String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}

try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//构建GenericBeanDefinition并设置className和parentName
AbstractBeanDefinition bd = createBeanDefinition(className, parent);

//对scope、abstract、lazy-init、autowire、dependency-check、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method、factory-bean属性进行解析。
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

//解析meta数据,用于注入。<meta key="format" value="BLURAY"/>
parseMetaElements(ele, bd);
//解析lookup-method数据,用于abstract方法动态生产bean。<lookup-method name="createCommand" bean="myCommand"/>
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
/**
* 解析replaced-method数据,用于根据参数类型替换方法。
* <replaced-method name="computeValue" replacer="replacementComputeValue">
*   <arg-type>String</arg-type>
* </replaced-method>
**/
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

// 解析constructor-arg,构造函数参数。可以index,type,name匹配。
parseConstructorArgElements(ele, bd);
// 解析property数据,用于属性赋值或注入。<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
parsePropertyElements(ele, bd);
/**
* 解析qualifier数据,用于注入,和meta类似。
* <qualifier type="MovieQualifier">
*    <attribute key="format" value="VHS"/>
*    <attribute key="genre" value="Action"/>
* </qualifier>
**/
parseQualifierElements(ele, bd);

bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));

return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}

return null;
}


解析完基本BeanDefinition后,需要调用
decorateBeanDefinitionIfRequired
对NameSpace属性进行解析如p:name=”test”。

到此定义在xml中Bean解析成GenericBeanDefinition完成。

2.ScannedGenericBeanDefinition

ScannedGenericBeanDefinition通过扫描Component,再通过MetadataReader获取AnnotationMetadata构建。重点关注MetadataReader的获取。

MetadataReader直接通过构造函数构建:

SimpleMetadataReader(Resource resource, ClassLoader classLoader) throws IOException {
InputStream is = new BufferedInputStream(resource.getInputStream());
ClassReader classReader;
try {
classReader = new ClassReader(is);
}
catch (IllegalArgumentException ex) {
throw new NestedIOException("ASM ClassReader failed to parse class file - " +
"probably due to a new Java class file version that isn't supported yet: " + resource, ex);
}
finally {
is.close();
}

AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader);
classReader.accept(visitor, ClassReader.SKIP_DEBUG);

this.annotationMetadata = visitor;
// (since AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor)
this.classMetadata = visitor;
this.resource = resource;
}


从源码可以看出, annotationMetadata 直接直接通过读取java class文件获取信息,后面bean的创建,就使用了这个annotationMetadata 。

3.ConfigurationClassBeanDefinition

ConfigurationClassBeanDefinition是定义在Configuration Class中的Bean,在这个bean创建是需要调用到Configuration Class中定义bean的方法。所以这个BeanDefinition的重点(特殊点)在于factoryMethodMetadata,即Configuration Class的对应的MethodMetaData。再通过解析Bean注解和Scope注解设置相应的值。

4.AnnotatedGenericBeanDefinition

@Import中定义的Bean,是作为Configuration Class来进行解析的,在ConfigurationClassParser

时已经解析成一个Configuration Class,并生成了metadata。后续和Component生成ScannedGenericBeanDefinition类似。spring.facotries中的EnableAutoConfiguration也是在ConfigurationClassParser的时候扫描得到Configuration Class。

5.ConfigurationClass

上面几个BeanDefinition创建是需要用的ConfigurationClass, ConfigurationClass是何时创建的,怎么创建的?

ConfigurationClassParser中创建ConfigurationClass源码:

protected final void parse(String className, String beanName) throws IOException {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}

protected final void parse(Class<?> clazz, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

public ConfigurationClass asConfigClass(ConfigurationClass importedBy) throws IOException {
if (this.source instanceof Class<?>) {
return new ConfigurationClass((Class<?>) this.source, importedBy);
}
return new ConfigurationClass((MetadataReader) this.source, importedBy);
}


第一个是在递归解析Component时创建。最后一个是在解析内部成员类和Import类。

6.getMergedBeanDefinition

在构建Bean实例是,都会获取MergedBeanDefinition,这个功能是把所有不是RootBeanDefinition实例的转成RootBeanDefinition,进行统一调用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: