Spring源代码分析(5)---propertyEditor(移花接木的自定义属性编辑器)

来源:互联网 发布:newbalance淘宝店 编辑:程序博客网 时间:2024/05/16 12:22
  1.     protected void initBeanWrapper(BeanWrapper bw) {
  2.         for (Iterator it = getCustomEditors().entrySet().iterator(); it.hasNext();) {
  3.             Map.Entry entry = (Map.Entry) it.next();
  4.             Class clazz = (Class) entry.getKey();
  5.             PropertyEditor editor = (PropertyEditor) entry.getValue();
  6.             bw.registerCustomEditor(clazz, editor);
  7.         }
  8.     }
在spring中可以把字符串映射成为其他类型的数据:

如:
 
  1. <bean name="ResourceInfo" class="org.corey.ResourceInfo">
  2.   <property name="resource1" value="classpath:test/corey.class"/>
  3.   <property name="resource2" value="classpath:test/corey.class"/>
  4. </bean>
气势在,ResourceInfo类中,resource1和resource2都是Resource类型的类,那么这里我们为什么可以将其设定位字符串形式的值呢,难道不会报错吗,那是因为我们同时有一下配置:
  1. <bean id="customEditorConfigurer" class="org.spring.framework.beans.factory.config.CustomEditorConfigurer">
  2. <property name="custromEditors">
  3.  <map>
  4.    <entry key="org.corey.ResourceInfo">
  5.       <bean class="org.springframework.core.io.ResourceEditor"/>
  6.    </entry>
  7. </map>
  8. </property>
  9. /bean>
  10.       


在这里,我们看见这个EditorConfigurer实现了我们上一节所说的BeanFactoryPostProcessor接口,那么,在BeanFactory加载类配置文件以前,这个EditorConfigurer到底做了什么呢,我们看一下:


  1. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  2.         if (this.customEditors != null) {
  3.             for (Iterator it = this.customEditors.keySet().iterator(); it.hasNext();) {
  4.                 Object key = it.next();
  5.                 Class requiredType = null;
  6.                 if (key instanceof Class) {
  7.                     requiredType = (Class) key;
  8.                 }
  9.                 else if (key instanceof String) {
  10.                     String className = (String) key;
  11.                     try {
  12.                         requiredType = ClassUtils.forName(className);
  13.                     }
  14.                     catch (ClassNotFoundException ex) {
  15.                         throw new BeanInitializationException(
  16.                                 "Could not load required type [" + className + "] for custom editor", ex);
  17.                     }
  18.                 }
  19.                 else {
  20.                     throw new BeanInitializationException(
  21.                             "Invalid key [" + key + "] for custom editor - needs to be Class or String");
  22.                 }
  23.                 Object value = this.customEditors.get(key);
  24.                 if (!(value instanceof PropertyEditor)) {
  25.                     throw new BeanInitializationException("Mapped value [" + value + "] for custom editor key [" +
  26.                             key + "] is not of required type [" + PropertyEditor.class.getName() + "]");
  27.                 }
  28.                 beanFactory.registerCustomEditor(requiredType, (PropertyEditor) value);
  29.             }
  30.         }
  31.     }
  32. }
EditorConfigurer类把自己的CustomEditors这个Map中的成员,加到了当前BEanFactory的customEditor中了,
key是指目标类,如上文中的org.corey.ResourceInfo类,value是指属性编辑器;


那么属性编辑器到底是什么呢,我们首先来看看PropertyEditor接口吧;

public interface PropertyEditor{

  public  void setAsText();
 
  public String getAsText();
 
}

他有一个默认实现是:PropertyEditorSupport类,从这个接口的方法,我们可以看出,这个接口可以把一个特定类型的对象序列化成为一个字符串,并且又能够把一个字符串反序列化成为一个对象;

如ResourceEditor:

  1. public class ResourceEditor extends PropertyEditorSupport {

  2.     private final ResourceLoader resourceLoader;


  3.     public ResourceEditor() {
  4.         this.resourceLoader = new DefaultResourceLoader();
  5.     }

  6.     public ResourceEditor(ResourceLoader resourceLoader) {
  7.         this.resourceLoader = resourceLoader;
  8.     }


  9.     public void setAsText(String text) {
  10.         if (StringUtils.hasText(text)) {
  11.             String locationToUse = resolvePath(text).trim();
  12.             setValue(this.resourceLoader.getResource(locationToUse));
  13.         }
  14.         else {
  15.             setValue(null);
  16.         }
  17.     }

  18.     
  19.     protected String resolvePath(String path) {
  20.         return SystemPropertyUtils.resolvePlaceholders(path);
  21.     }

  22. }
那到底,BeanFactory中在什么时候自动的把字符串替换成为了Resource类型的对象呢,这时候我们就必须看BeanFactory类了:

transformedBeanName(name);:bean名字转换,比如去掉&,把别名改写位正式的名字等等;
transformedBeanName(name);根据名字拿到这个Beanname对应的BeanDefinition(已介绍);
checkMergedBeanDefinition(mergedBeanDefinition, beanName, requiredType, args);查看这个bean定义是不是抽象的;
createBean(beanName, mergedBeanDefinition, args):正式建立一个实例;



createBean()是在AbstractAutoWireBeanFactory中实现的,在这个里面做了创建实例bean的工作,如下:


*[mergedBeanDefinition.getDependsOn().length]getBean(mergedBeanDefinition.getDependsOn());:循环这个bean所依赖的bean,然后getBean();达到预先createBean();这个被依赖类的作用;

instantiateBean(beanName, mergedBeanDefinition);根据所提供的构造函数,或者默认构造函数,或相应的诸如规则调用构造函数生成实例;

populateBean(beanName, mergedBeanDefinition, instanceWrapper);对属性进行注入;

applyBeanPostProcessorsBeforeInitialization(bean, beanName);调用
BeanPostProcessorsBeforeInitialization

invokeInitMethods(beanName, bean, mergedBeanDefinition);调用初始化方法;

applyBeanPostProcessorsAfterInitialization(bean, beanName);;调用
BeanPostProcessorsAfterInitialization

我们重点来看下
instantiateBean:
  1.     protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mergedBeanDefinition)
  2.             throws BeansException {
  3.         Object beanInstance = getInstantiationStrategy().instantiate(mergedBeanDefinition, beanName, this);
  4.         BeanWrapper bw = new BeanWrapperImpl(beanInstance);
  5.         initBeanWrapper(bw);
  6.         return bw;
  7.     }


  1.     protected void initBeanWrapper(BeanWrapper bw) {
  2.         for (Iterator it = getCustomEditors().entrySet().iterator(); it.hasNext();) {
  3.             Map.Entry entry = (Map.Entry) it.next();
  4.             Class clazz = (Class) entry.getKey();
  5.             PropertyEditor editor = (PropertyEditor) entry.getValue();
  6.             bw.registerCustomEditor(clazz, editor);
  7.         }
  8.     }
 BeanWrapper bw中含有cachedIntrospectionResults,包括这个pojo类的所有属性的米的描述;


populateBean:
  1.     protected void populateBean(String beanName, RootBeanDefinition mergedBeanDefinition, BeanWrapper bw)
  2.             throws BeansException {

  3.         PropertyValues pvs = mergedBeanDefinition.getPropertyValues();

  4.         if (mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
  5.                 mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  6.             MutablePropertyValues mpvs = new MutablePropertyValues(pvs);

  7.             // Add property values based on autowire by name if applicable.
  8.             if (mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
  9.                 autowireByName(beanName, mergedBeanDefinition, bw, mpvs);
  10.             }

  11.             // Add property values based on autowire by type if applicable.
  12.             if (mergedBeanDefinition.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
  13.                 autowireByType(beanName, mergedBeanDefinition, bw, mpvs);
  14.             }

  15.             pvs = mpvs;
  16.         }

  17.         checkDependencies(beanName, mergedBeanDefinition, bw, pvs);
  18.         applyPropertyValues(beanName, mergedBeanDefinition, bw, pvs);
  19.     }
checkDependencies:检查dependcheck,确保制定的属性被设置;

applyPropertyValues:
  1. private void applyPropertyValues(
  2.             String beanName, RootBeanDefinition mergedBeanDefinition, BeanWrapper bw, PropertyValues pvs)
  3.             throws BeansException {
  4.         if (pvs == null) {
  5.             return;
  6.         }
  7.         BeanDefinitionValueResolver valueResolver =
  8.                 new BeanDefinitionValueResolver(this, beanName, mergedBeanDefinition);
  9.         // Create a deep copy, resolving any references for values.
  10.         MutablePropertyValues deepCopy = new MutablePropertyValues();
  11.         PropertyValue[] pvArray = pvs.getPropertyValues();
  12.         for (int i = 0; i < pvArray.length; i++) {
  13.             PropertyValue pv = pvArray[i];
  14.             Object resolvedValue =
  15.                     valueResolver.resolveValueIfNecessary("bean property '" + pv.getName() + "'", pv.getValue());
  16.             deepCopy.addPropertyValue(pvArray[i].getName(), resolvedValue);
  17.         }
  18.         // Set our (possibly massaged) deep copy.
  19.         try {
  20.             // Synchronize if custom editors are registered.
  21.             // Necessary because PropertyEditors are not thread-safe.
  22.             if (!getCustomEditors().isEmpty()) {
  23.                 synchronized (this) {
  24.                     bw.setPropertyValues(deepCopy);
  25.                 }
  26.             }
  27.             else {
  28.                 bw.setPropertyValues(deepCopy);
  29.             }
  30.         }
  31.         catch (BeansException ex) {
  32.             // Improve the message by showing the context.
  33.             throw new BeanCreationException(
  34.                     mergedBeanDefinition.getResourceDescription(), beanName, "Error setting property values", ex);
  35.         }
  36.     }
  1. protected Object doTypeConversionIfNecessary(String propertyName, String fullPropertyName,
  2.             Object oldValue, Object newValue, Class requiredType) throws TypeMismatchException {
  3.         Object convertedValue = newValue;
  4.         // Custom editor for this type?
  5.         PropertyEditor pe = findCustomEditor(requiredType, fullPropertyName);
  6.         // Value not of required type?
  7.         if (pe != null ||
  8.                 (requiredType != null &&
  9.                 (requiredType.isArray() || !requiredType.isInstance(convertedValue)))) {
  10.             if (requiredType != null) {
  11.                 if (pe == null) {
  12.                     // No custom editor -> check BeanWrapperImpl's default editors.
  13.                     pe = (PropertyEditor) getDefaultEditor(requiredType);
  14.                     if (pe == null) {
  15.                         // No BeanWrapper default editor -> check standard JavaBean editors.
  16.                         pe = PropertyEditorManager.findEditor(requiredType);
  17.                     }
  18.                 }
  19.             }
  20.             if (pe != null && !(convertedValue instanceof String)) {
  21.                 // Not a String -> use PropertyEditor's setValue.
  22.                 // With standard PropertyEditors, this will return the very same object;
  23.                 // we just want to allow special PropertyEditors to override setValue
  24.                 // for type conversion from non-String values to the required type.
  25.                 try {
  26.                     pe.setValue(convertedValue);
  27.                     Object newConvertedValue = pe.getValue();
  28.                     if (newConvertedValue != convertedValue) {
  29.                         convertedValue = newConvertedValue;
  30.                         // Reset PropertyEditor: It already did a proper conversion.
  31.                         // Don't use it again for a setAsText call.
  32.                         pe = null;
  33.                     }
  34.                 }
  35.                 catch (IllegalArgumentException ex) {
  36.                     throw new TypeMismatchException(
  37.                             createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType, ex);
  38.                 }
  39.             }
  40.             if (requiredType != null && !requiredType.isArray() && convertedValue instanceof String[]) {
  41.                 // Convert String array to a comma-separated String.
  42.                 // Only applies if no PropertyEditor converted the String array before.
  43.                 // The CSV String will be passed into a PropertyEditor's setAsText method, if any.
  44.                 if (logger.isDebugEnabled()) {
  45.                     logger.debug("Converting String array to comma-delimited String [" + convertedValue + "]");
  46.                 }
  47.                 convertedValue = StringUtils.arrayToCommaDelimitedString((String[]) convertedValue);
  48.             }
  49.             if (pe != null && convertedValue instanceof String) {
  50.                 // Use PropertyEditor's setAsText in case of a String value.
  51.                 if (logger.isDebugEnabled()) {
  52.                     logger.debug("Converting String to [" + requiredType + "] using property editor [" + pe + "]");
  53.                 }
  54.                 try {
  55.                   //转换的点在这里,你可以清晰的看见;;;;;
  56.                     pe.setValue(oldValue);
  57.                     pe.setAsText((String) convertedValue);
  58.                     convertedValue = pe.getValue();
  59.                 }
  60.                 catch (IllegalArgumentException ex) {
  61.                     throw new TypeMismatchException(
  62.                             createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType, ex);
  63.                 }
  64.             }
  65.             if (requiredType != null) {
  66.                 // Array required -> apply appropriate conversion of elements.
  67.                 if (requiredType.isArray()) {
  68.                     Class componentType = requiredType.getComponentType();
  69.                     if (convertedValue instanceof Collection) {
  70.                         // Convert Collection elements to array elements.
  71.                         Collection coll = (Collection) convertedValue;
  72.                         Object result = Array.newInstance(componentType, coll.size());
  73.                         int i = 0;
  74.                         for (Iterator it = coll.iterator(); it.hasNext(); i++) {
  75.                             Object value = doTypeConversionIfNecessary(
  76.                                     propertyName, propertyName + PROPERTY_KEY_PREFIX + i + PROPERTY_KEY_SUFFIX,
  77.                                     null, it.next(), componentType);
  78.                             Array.set(result, i, value);
  79.                         }
  80.                         return result;
  81.                     }
  82.                     else if (convertedValue != null && convertedValue.getClass().isArray()) {
  83.                         // Convert Collection elements to array elements.
  84.                         int arrayLength = Array.getLength(convertedValue);
  85.                         Object result = Array.newInstance(componentType, arrayLength);
  86.                         for (int i = 0; i < arrayLength; i++) {
  87.                             Object value = doTypeConversionIfNecessary(
  88.                                     propertyName, propertyName + PROPERTY_KEY_PREFIX + i + PROPERTY_KEY_SUFFIX,
  89.                                     null, Array.get(convertedValue, i), componentType);
  90.                             Array.set(result, i, value);
  91.                         }
  92.                         return result;
  93.                     }
  94.                     else if (convertedValue != null) {
  95.                         // A plain value: convert it to an array with a single component.
  96.                         Object result = Array.newInstance(componentType, 1);
  97.                         Object value = doTypeConversionIfNecessary(
  98.                                 propertyName, propertyName + PROPERTY_KEY_PREFIX + 0 + PROPERTY_KEY_SUFFIX,
  99.                                 null, convertedValue, componentType);
  100.                         Array.set(result, 0, value);
  101.                         return result;
  102.                     }
  103.                 }
  104.                 // If the resulting value definitely doesn't match the required type,
  105.                 // try field lookup as fallback. If no matching field found,
  106.                 // throw explicit TypeMismatchException with full context information.
  107.                 if (convertedValue != null && !requiredType.isPrimitive() &&
  108.                         !requiredType.isInstance(convertedValue)) {
  109.                     // In case of String value, try to find matching field (for JDK 1.5
  110.                     // enum or custom enum with values defined as static fields).
  111.                     if (convertedValue instanceof String) {
  112.                         try {
  113.                             Field enumField = requiredType.getField((String) convertedValue);
  114.                             return enumField.get(null);
  115.                         }
  116.                         catch (Exception ex) {
  117.                             if (logger.isDebugEnabled()) {
  118.                                 logger.debug("Field [" + convertedValue + "] isn't an enum value", ex);
  119.                             }
  120.                         }
  121.                     }
  122.                     // Definitely doesn't match: throw TypeMismatchException.
  123.                     throw new TypeMismatchException(
  124.                             createPropertyChangeEvent(fullPropertyName, oldValue, newValue), requiredType);
  125.                 }
  126.             }
  127.         }
  128.         return convertedValue;
  129.     }

原创粉丝点击