随笔 - 1639  文章 - 579 评论 - 373 trackbacks - 0

  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的面纱,希望能起到抛砖引玉的功能,以飨读者。

 

posted on 2014-12-30 17:14 一天不进步,就是退步 阅读(...) 评论(...) 编辑 收藏