spring beans源码解读之--Bean的定义及包装

时间:2021-07-10 01:56:47

bean的定义,包装是java bean的基础。再怎么强调它的重要性都不为过,因此深入 了解这块的代码对以后的代码研究可以起到事半功倍的功效。

1. Bean的定义BeanDefinition

1.1 BeanDefinition 作用

一个BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。BeanDefinition仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor 例如PropertyPlaceHolderConfigure 能够检索并修改属性值和别的bean的元数据。

1.2 BeanDefinition的继承关系

父接口:
AttributeAccessor, BeanMetadataElement
子接口:
AnnotatedBeanDefinition
子类:
AbstractBeanDefinition, AnnotatedGenericBeanDefinition, ChildBeanDefinition, GenericBeanDefinition, RootBeanDefinition, ScannedGenericBeanDefinition

其中,AttributeAccessor接口定义了最基本的对任意对象的元数据的修改或者获取,主要方法有:

String[] attributeNames()
Object getAttribute(String name)
boolean hasAttribute(String name)
Object removeAttribute(String name)
void setAttribute(String name, Object value)

BeanMetadataElement接口提供了一个getResource()方法,用来传输一个可配置的源对象。

1.3 BeanDefinition的抽象类AbstractBeanDefinition

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
}

其中,BeanMetadataAttributeAccessor接口既实现了BeanMetadataElement接口提供的getResource()方法也提供了AttributeAccessorSupport 针对属性的增删改查,如上AttributeAccessor的方法。

public class BeanMetadataAttributeAccessor extends AttributeAccessorSupport implements BeanMetadataElement {
}

我们来看看一个抽象的beanDefinition 的创建涉及到哪些属性?

构造方法之一,创建一个新的默认设置的AbstractBeanDefinition,如下面代码所示,具体信息也可以参考BeanDefinitionDefaults这个类。

构造方法之二,根据构造参数值和属性参数值来创建。

    /**
* Create a new AbstractBeanDefinition with default settings.
*/
protected AbstractBeanDefinition() {
this(null, null);
} /**
* Create a new AbstractBeanDefinition with the given
* constructor argument values and property values.
*/
protected AbstractBeanDefinition(ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
setConstructorArgumentValues(cargs);
setPropertyValues(pvs);
}

构造方法之三是深复制一个原有的beandefinition。

/**
* Create a new AbstractBeanDefinition as a deep copy of the given
* bean definition.
* @param original the original bean definition to copy from
*/
protected AbstractBeanDefinition(BeanDefinition original) {
setParentName(original.getParentName());
setBeanClassName(original.getBeanClassName());
setFactoryBeanName(original.getFactoryBeanName());
setFactoryMethodName(original.getFactoryMethodName());
setScope(original.getScope());
setAbstract(original.isAbstract());
setLazyInit(original.isLazyInit());
setRole(original.getRole());
setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues()));
setPropertyValues(new MutablePropertyValues(original.getPropertyValues()));
setSource(original.getSource());
copyAttributesFrom(original); if (original instanceof AbstractBeanDefinition) {
AbstractBeanDefinition originalAbd = (AbstractBeanDefinition) original;
if (originalAbd.hasBeanClass()) {
setBeanClass(originalAbd.getBeanClass());
}
setAutowireMode(originalAbd.getAutowireMode());
setDependencyCheck(originalAbd.getDependencyCheck());
setDependsOn(originalAbd.getDependsOn());
setAutowireCandidate(originalAbd.isAutowireCandidate());
copyQualifiersFrom(originalAbd);
setPrimary(originalAbd.isPrimary());
setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed());
setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
setInitMethodName(originalAbd.getInitMethodName());
setEnforceInitMethod(originalAbd.isEnforceInitMethod());
setDestroyMethodName(originalAbd.getDestroyMethodName());
setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod());
setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides()));
setSynthetic(originalAbd.isSynthetic());
setResource(originalAbd.getResource());
}
else {
setResourceDescription(original.getResourceDescription());
}
}

上述三个方法涉及到的接口和类有:

ConstructorArgumentValues:构造参数,保存了构造方法所有的参数值,通常作为bean definition的一部分来使用。它不仅支持类型匹配的普通参数,也支持根据参数列表中的索引位置来提供参数。提供了两个变量来保存参数:带索引的和不带索引的

public class ConstructorArgumentValues {

    private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<Integer, ValueHolder>(0);

    private final List<ValueHolder> genericArgumentValues = new LinkedList<ValueHolder>();
}

MutablePropertyValues:PropertyValues接口的默认实现,支持对属性的简单操作,为构造方法提供深度复制和使用map获取构造的支持。

1.4 bean definition实现类ChildBeanDefinition, GenericBeanDefinition, RootBeanDefinition

 1.4.1 ChildBeanDefinition是一种bean definition,它可以继承它父类的设置,即ChildBeanDefinition对RootBeanDefinition有一定的依赖关系。

  ChildBeanDefinition从父类继承构造参数值,属性值并可以重写父类的方法,同时也可以增加新的属性或者方法。(类同于java类的继承关系)。若指定初始化方法,销毁方法或者静态工厂方法,  ChildBeanDefinition将重写相应父类的设置。depends on,autowire mode,dependency check,sigleton,lazy init 一般由子类自行设定。

注意:从spring 2.5 开始,提供了一个更好的注册bean definition类GenericBeanDefinition,它支持动态定义父依赖,方法是GenericBeanDefinition.setParentName(java.lang.String),GenericBeanDefinition可以有效的替代ChildBeanDefinition的绝大分部使用场合。

1.4.2 GenericBeanDefinition是一站式的标准bean definition,除了具有指定类、可选的构造参数值和属性参数这些其它bean definition一样的特性外,它还具有通过parenetName属性来灵活设置parent bean definition。

通常, GenericBeanDefinition用来注册用户可见的bean definition(可见的bean definition意味着可以在该类bean definition上定义post-processor来对bean进行操作,甚至为配置parent name做扩展准备)。RootBeanDefinition / ChildBeanDefinition用来预定义具有parent/child关系的bean definition。

1.4.3 RootBeanDefinition

一个RootBeanDefinition定义表明它是一个可合并的bean definition:即在spring beanFactory运行期间,可以返回一个特定的bean。RootBeanDefinition可以作为一个重要的通用的bean definition 视图。

RootBeanDefinition用来在配置阶段进行注册bean definition。然后,从spring 2.5后,编写注册bean definition有了更好的的方法:GenericBeanDefinition。GenericBeanDefinition支持动态定义父类依赖,而非硬编码作为root bean definition。

涉及到的类:BeanDefinitionHolder,根据名称或者别名持有beanDefinition。可以为一个内部bean 注册为placeholder。

BeanDefinitionHolder也可以编写一个内部bean definition的注册,如果你不关注BeanNameAware等,完全可以使用RootBeanDefinition或者ChildBeanDefinition来替代。

2. Bean的包装BeanWrapper

2.1 作用:提供对标准javabean的分析和操作方法:单个或者批量获取和设置属性值,获取属性描述符,查询属性的可读性和可写性等。支持属性的嵌套设置,深度没有限制。

2.2 继承关系:

public interface BeanWrapper extends ConfigurablePropertyAccessor {
} public interface ConfigurablePropertyAccessor extends PropertyAccessor, PropertyEditorRegistry, TypeConverter {
}

其中,ConfigurablePropertyAccessor 接口封装了PropertyAccessor的配置方法,同时继承了PropertyEditorRegistry接口,具有了对PropertyEditor进行管理的方法。该接口的固有方法:

ConversionService getConversionService() 返回关联的ConversionService,如果存在的话。
boolean isExtractOldValueForEditor() 返回标示位。如果为true,表示当使用属性编辑器编辑一个属性的值时提取旧的属性值,如果为false,则表示不提取旧值。
void setConversionService(ConversionService conversionService) conversionservice是从spring3.0引入的,可以作为java bean 属性编辑器的替代功能,作用是改变属性的值。
void setExtractOldValueForEditor(boolean extractOldValueForEditor) 设置是否提取旧的属性值标示位,如上描述。

另外,ConfigurablePropertyAccessor 接口继承的方法有:

从PropertyAccessor继承的方法有:getPropertyType, getPropertyTypeDescriptor, getPropertyValue, isReadableProperty, isWritableProperty, setPropertyValue, setPropertyValue, setPropertyValues, setPropertyValues, setPropertyValues, setPropertyValues;

从PropertyEditorRegistry继承的方法有:findCustomEditor, registerCustomEditor, registerCustomEditor;

从TypeConverter 继承的方法有:convertIfNecessary, convertIfNecessary, convertIfNecessary 。

2.3 BeanWrapper的实现类:BeanWrapperImpl

BeanWrapperImpl作用:可以根据需求,将集合与数组的值转换到对应目标对象的集合和数组。自定义的属性编辑器通过属性编辑器的setValue,setAsText方法实现上述的转换功能。

BeanWrapperImpl 默认的PropertyEditor的实现如下:(PropertyEditorRegistrySupport.java)

private void createDefaultEditors() {
this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64); // Simple editors, without parameterization capabilities.
// The JDK does not contain a default editor for any of these target types.
this.defaultEditors.put(Charset.class, new CharsetEditor());
this.defaultEditors.put(Class.class, new ClassEditor());
this.defaultEditors.put(Class[].class, new ClassArrayEditor());
this.defaultEditors.put(Currency.class, new CurrencyEditor());
this.defaultEditors.put(File.class, new FileEditor());
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
this.defaultEditors.put(Locale.class, new LocaleEditor());
this.defaultEditors.put(Pattern.class, new PatternEditor());
this.defaultEditors.put(Properties.class, new PropertiesEditor());
this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
this.defaultEditors.put(URI.class, new URIEditor());
this.defaultEditors.put(URL.class, new URLEditor());
this.defaultEditors.put(UUID.class, new UUIDEditor());
if (zoneIdClass != null) {
this.defaultEditors.put(zoneIdClass, new ZoneIdEditor());
} // Default instances of collection editors.
// Can be overridden by registering custom instances of those as custom editors.
this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class)); // Default editors for primitive arrays.
this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
this.defaultEditors.put(char[].class, new CharArrayPropertyEditor()); // The JDK does not contain a default editor for char!
this.defaultEditors.put(char.class, new CharacterEditor(false));
this.defaultEditors.put(Character.class, new CharacterEditor(true)); // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true)); // The JDK does not contain default editors for number wrapper types!
// Override JDK primitive number editors with our own CustomNumberEditor.
this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true)); // Only register config value editors if explicitly requested.
if (this.configValueEditorsActive) {
StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
this.defaultEditors.put(String[].class, sae);
this.defaultEditors.put(short[].class, sae);
this.defaultEditors.put(int[].class, sae);
this.defaultEditors.put(long[].class, sae);
}
}

其中涉及到很多编辑器,在此就不赘叙了,如有兴趣,可以自行查找。

3. 小结:

bean的定义,包装是java bean的基础。可以这么说,这一块是spring的基石。本文仅仅揭开spring 中java bean的面纱,希望能起到抛砖引玉的功能,以飨读者。