BeanDefinition数据流

BeanDefinition是Spring配置文件中bean定义的内存表现形式,我们先来看看bean的创建。在下图中不同的元素的解析路线用不同的颜色标注
主线部分  
  1. 实例化xmlApplicationContext
  2. 实例化XmlBeanDefinitionReader
  3. ResourceLoader定位bean文件
  4. XmlBeanDefinitionReader读入Resource
  5. DefaultBeanDefinitionDocumentReader解析Document
  6. 默认命名空间判断
  7. import元素判断
  8. alias元素判断
  9. beans元素递归
非默认bean命名空间处理,如AOP
  1. 读取多个jar包中的META-INF/spring.handlers
  2. DefaultNamespaceResolver解析spring.handlers
  3.        文件,取得元素命名空间对应的NamespaceHandler
  4. NamespaceHandler解析Element元素
  5. 根据不同的Handler会生成或ComponentDefinition或BeanDefinition
  6. 注册BeanDefinition

import元素处理部分
  1.    重复主线中的3,4,5步
alias元素处理部分
  1.    注册标志和别名
bean元素处理部分
  1.    通过BeanfinitionParserDelegate解析bean元素
  2.    注册BeanDefinitionHolder






在解析bean.xml的过程中,用"<property....."作为类的属性值,与之对应的值的定义方式不同反应不同的数据结构,

1.<property name="foo" ref="bean"/>
2.<property name="foo" value="beanString"/>
3.<property name="foo">
  <bean class=""/>
</property>
....

beanDefinition必须存储这些信息,那BeanDefinition定义中,可以看到属性值设置信息在MutablePropertyValues 中,当然<constructor-arg/>类似,存储在ConstructorArgumentValues
ConstructorArgumentValues getConstructorArgumentValues();
MutablePropertyValues getPropertyValues();

不同的Element或Attribute对应不同的属性值的结构列表如下



这些数据类型会在getBean初始化设值时转化为必要值引用类型,对于值是beanDefinitionHolder的将生成为一个prototype的bean。
public Object resolveValueIfNecessary(Object argName, Object value) {
		// We must check each value to see whether it requires a runtime reference
		// to another bean to be resolved.
		if (value instanceof RuntimeBeanReference) {
			RuntimeBeanReference ref = (RuntimeBeanReference) value;
			return resolveReference(argName, ref);
		}
		else if (value instanceof RuntimeBeanNameReference) {
			String refName = ((RuntimeBeanNameReference) value).getBeanName();
			refName = String.valueOf(evaluate(refName));
			if (!this.beanFactory.containsBean(refName)) {
				throw new BeanDefinitionStoreException(
						"Invalid bean name '" + refName + "' in bean reference for " + argName);
			}
			return refName;
		}
		else if (value instanceof BeanDefinitionHolder) {
			// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
			BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
			return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
		}
		else if (value instanceof BeanDefinition) {
			// Resolve plain BeanDefinition, without contained name: use dummy name.
			BeanDefinition bd = (BeanDefinition) value;
			return resolveInnerBean(argName, "(inner bean)", bd);
		}
		else if (value instanceof ManagedArray) {
			// May need to resolve contained runtime references.
			ManagedArray array = (ManagedArray) value;
			Class elementType = array.resolvedElementType;
			if (elementType == null) {
				String elementTypeName = array.getElementTypeName();
				if (StringUtils.hasText(elementTypeName)) {
					try {
						elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
						array.resolvedElementType = elementType;
					}
					catch (Throwable ex) {
						// Improve the message by showing the context.
						throw new BeanCreationException(
								this.beanDefinition.getResourceDescription(), this.beanName,
								"Error resolving array type for " + argName, ex);
					}
				}
				else {
					elementType = Object.class;
				}
			}
			return resolveManagedArray(argName, (List<?>) value, elementType);
		}
		else if (value instanceof ManagedList) {
			// May need to resolve contained runtime references.
			return resolveManagedList(argName, (List<?>) value);
		}
		else if (value instanceof ManagedSet) {
			// May need to resolve contained runtime references.
			return resolveManagedSet(argName, (Set<?>) value);
		}
		else if (value instanceof ManagedMap) {
			// May need to resolve contained runtime references.
			return resolveManagedMap(argName, (Map<?, ?>) value);
		}
		else if (value instanceof ManagedProperties) {
			Properties original = (Properties) value;
			Properties copy = new Properties();
			for (Map.Entry propEntry : original.entrySet()) {
				Object propKey = propEntry.getKey();
				Object propValue = propEntry.getValue();
				if (propKey instanceof TypedStringValue) {
					propKey = evaluate((TypedStringValue) propKey);
				}
				if (propValue instanceof TypedStringValue) {
					propValue = evaluate((TypedStringValue) propValue);
				}
				copy.put(propKey, propValue);
			}
			return copy;
		}
		else if (value instanceof TypedStringValue) {
			// Convert value to target type here.
			TypedStringValue typedStringValue = (TypedStringValue) value;
			Object valueObject = evaluate(typedStringValue);
			try {
				Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
				if (resolvedTargetType != null) {
					return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
				}
				else {
					return valueObject;
				}
			}
			catch (Throwable ex) {
				// Improve the message by showing the context.
				throw new BeanCreationException(
						this.beanDefinition.getResourceDescription(), this.beanName,
						"Error converting typed String value for " + argName, ex);
			}
		}
		else {
			return evaluate(value);
		}
	}

转化规则如下

当实例都准备好之后,在匹配之前支持做类型转换
Spring使用java bean规范中的PropertyEditors解决中Object和String之间的转换 。我们可以自定义java.beans.PropertyEditor实现,然后注册到Spring容器中。比如经常使用的场景是解析bean.xml时。org.springframework.beans.propertyeditors包下的所有编辑器被Spring支持,Spring通过java.bean.PropertyEditorManager设置这种搜索路径。经典实现中,将会查找class bean包路径+"Editor"


Foo类同包下面有个FooEditor
com
  chank
    pop
      Foo
      FooEditor   // the PropertyEditor for the Foo class

在使用JAVA BEAN自省机制之前,可以定义Foo类的BeanInfo
com
  chank
    pop
      Foo
      FooBeanInfo   // the BeanInfo for the Foo class
public class FooBeanInfo extends SimpleBeanInfo {

    public PropertyDescriptor[] getPropertyDescriptors() {
        try {
            final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);
            PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) {
                public PropertyEditor createPropertyEditor(Object bean) {
                    return numberPE;
                };
            };
            return new PropertyDescriptor[] { ageDescriptor };
        }
        catch (IntrospectionException ex) {
            throw new Error(ex.toString());
        }
    }
}

接下来进行注册
将ExoticType 实例注入到DependsOnExoticType 中,很显然,我们需要
ExoticType对应的Editor将字符串转化为ExoticType 以注入

package example;

public class ExoticType {

    private String name;

    public ExoticType(String name) {
        this.name = name;
    }
}

public class DependsOnExoticType {

    private ExoticType type;

    public void setType(ExoticType type) {
        this.type = type;
    }
}

只是一个ExoticType 名字
<bean id="sample" class="example.DependsOnExoticType">
    <property name="type" value="aNameForExoticType"/>
</bean>

PropertyEditor实现
// converts string representation to ExoticType object
package example;

public class ExoticTypeEditor extends PropertyEditorSupport {

    public void setAsText(String text) {
        setValue(new ExoticType(text.toUpperCase()));
    }
}

我们将使用CustomEditorConfigurer注册,这是一个BeanFactoryPostProcessor Bean,在ApplicationContext生命周期中自动调用
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  <property name="customEditors">
    <map>
      <entry key="example.ExoticType" value="example.ExoticTypeEditor"/>
    </map>
  </property>
</bean>

如果要使用多个Editor,则还可以实现PropertyEditorRegistrar 接口,在实现中编程注册;显然多了一层包装。
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {

    public void registerCustomEditors(PropertyEditorRegistry registry) {

        // it is expected that new PropertyEditor instances are created
        registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());

        // you could register as many custom property editors as are required here...
    }
}

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="propertyEditorRegistrars">
        <list>
            <ref bean="customPropertyEditorRegistrar"/>
        </list>
    </property>
</bean>

<bean id="customPropertyEditorRegistrar"
      class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>

java bean风格的类型转化只在String与Object之间,那如果Object和Object,则java bean标准转化机制显得不够用。spring 3引入了core.convert包提供更加一般化的类型转换。使用泛型机制,强制类型。
public interface Converter<S, T> {

    T convert(S source);

}
//简单实现StringToInteger 
final class StringToInteger implements Converter<String, Integer> {

    public Integer convert(String source) {
        return Integer.valueOf(source);
    }

}

当仅仅关注某一类型的转化器时,ConverterFactory有了用武之地。
public interface ConverterFactory<S, R> {

    <T extends R> Converter<S, T> getConverter(Class<T> targetType);

}
//将字符串转化为一个枚举类型的factory
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {

    public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToEnumConverter(targetType);
    }

    private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {

        private Class<T> enumType;

        public StringToEnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }

        public T convert(String source) {
            return (T) Enum.valueOf(this.enumType, source.trim());
        }
    }
}

GenericConverter没有泛型化
package org.springframework.core.convert.converter;

public interface GenericConverter {

    public Set<ConvertiblePair> getConvertibleTypes();

    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

}

ConditionalGenericConverter想执行转换之前知道是否能够转换
public interface ConditionalGenericConverter extends GenericConverter {

    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);

}

ConversionService 实现具体的转换逻辑。spring中大多数现象了
ConversionService 的同时也实现了ConverterRegistry,ConverterRegistry用于注册转换器,一般来说,ConversionService 实现需要使用转换器了解源对象和目标对象的类型。GenericConversionService就是这样的一个实现。
package org.springframework.core.convert;

public interface ConversionService {

    boolean canConvert(Class<?> sourceType, Class<?> targetType);

    <T> T convert(Object source, Class<T> targetType);

    boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);

    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

}

我们将使用ConversionServiceFactoryBean注册转换器和GenericConversionService
<bean id="conversionService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="example.MyCustomConverter"/>
        </list>
    </property>
</bean>

猜你喜欢

转载自tmmh.iteye.com/blog/1896655