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


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

  • 相关阅读:
    mysql零碎问题合集
    mysql 纵表转横表 需要用join不能直接where连接
    eclipse导出可执行jar包 报main function not found错误
    shell脚本将mysql查询结果制作成csv格式
    linux shell中把句子中的单词提取作为变量值 主要是使用了数组
    linux下文件字符编码转换
    Banner使用
    recyclerview的博客网址需要的权限
    okhttp权限
    Okhttp代码
  • 原文地址:https://www.cnblogs.com/davidwang456/p/4192318.html
Copyright © 2020-2023  润新知