1. 程式人生 > >java冷知識:java bean內省模式以及spring bean的關聯

java冷知識:java bean內省模式以及spring bean的關聯

最近一直整理著搜尋引擎相關的主題,後續也準備多分享一些spring相關的技術。正所謂溫故而知新,java bean內省模式對spring bean的影響非常深,真可謂是青出於藍而勝於藍。

目錄

1. JavaBean Introspector

1.1 BeanDescriptor

1.2 MethodDescriptor

1.3 PropertyDescriptor

1.4 ParameterDescriptor

1.5 Introspector

1.6 屬性變化監聽

2. spring bean

​2.1 PropertyEditorRegistry

2.2 PropertyEditorRegistrar

2.3 CustomEditorConfigurer


1. JavaBean Introspector

Java的內省機制其實是基於JavaBean的,那麼,什麼是JavaBean哪?我們可以這樣說,我們在專案中經常用到的Model可以充當JavaBean,其實我對於JavaBean的理解是它要滿足以下幾個特徵:

  • 有屬性可以儲存的成員變數
  • 有空參構造方法
  • 屬性由對應get/set方法。

而內省(Introspector) 是Java語言對JavaBean類屬性

事件的一種預設處理方法。類User中有屬性userName,那我們可以通過getUserName,setUserName來得到其值或者設定新的值。通過getUserName/setUserName來訪問userName屬性,這就是預設的規則。Sun JDK中提供了一套API用來訪問某個屬性的getter/setter方法,這就是內省。

1.1 BeanDescriptor

BeanDescriptor就是bean描述符,原始碼

package java.beans;

public class BeanDescriptor extends FeatureDescriptor {
    private Reference<? extends Class<?>> beanClassRef;
    private Reference<? extends Class<?>> customizerClassRef;

    public BeanDescriptor(Class<?> var1) {
        this(var1, (Class)null);
    }

    public BeanDescriptor(Class<?> var1, Class<?> var2) {
        this.beanClassRef = getWeakReference(var1);
        this.customizerClassRef = getWeakReference(var2);

        String var3;
        for(var3 = var1.getName(); var3.indexOf(46) >= 0; var3 = var3.substring(var3.indexOf(46) + 1)) {
            ;
        }

        this.setName(var3);
    }

    public Class<?> getBeanClass() {
        return this.beanClassRef != null?(Class)this.beanClassRef.get():null;
    }

    public Class<?> getCustomizerClass() {
        return this.customizerClassRef != null?(Class)this.customizerClassRef.get():null;
    }

    BeanDescriptor(BeanDescriptor var1) {
        super(var1);
        this.beanClassRef = var1.beanClassRef;
        this.customizerClassRef = var1.customizerClassRef;
    }

    void appendTo(StringBuilder var1) {
        appendTo(var1, "beanClass", this.beanClassRef);
        appendTo(var1, "customizerClass", this.customizerClassRef);
    }
}

1.2 MethodDescriptor

MethodDescriptor就是方法描述符

package java.beans;
public class MethodDescriptor extends FeatureDescriptor {

    private final MethodRef methodRef = new MethodRef();

    private String[] paramNames;

    private List<WeakReference<Class<?>>> params;

    private ParameterDescriptor parameterDescriptors[];

    /**
     * Constructs a <code>MethodDescriptor</code> from a
     * <code>Method</code>.
     *
     * @param method    The low-level method information.
     */
    public MethodDescriptor(Method method) {
        this(method, null);
    }


    /**
     * Constructs a <code>MethodDescriptor</code> from a
     * <code>Method</code> providing descriptive information for each
     * of the method's parameters.
     *
     * @param method    The low-level method information.
     * @param parameterDescriptors  Descriptive information for each of the
     *                          method's parameters.
     */
    public MethodDescriptor(Method method,
                ParameterDescriptor parameterDescriptors[]) {
        setName(method.getName());
        setMethod(method);
        this.parameterDescriptors = (parameterDescriptors != null)
                ? parameterDescriptors.clone()
                : null;
    }
}

1.3 PropertyDescriptor

PropertyDescriptor就是欄位描述符

package java.beans;
public class PropertyDescriptor extends FeatureDescriptor {

    private Reference<? extends Class<?>> propertyTypeRef;
    private final MethodRef readMethodRef = new MethodRef();
    private final MethodRef writeMethodRef = new MethodRef();
    private Reference<? extends Class<?>> propertyEditorClassRef;

    private boolean bound;
    private boolean constrained;

    // The base name of the method name which will be prefixed with the
    // read and write method. If name == "foo" then the baseName is "Foo"
    private String baseName;

    private String writeMethodName;
    private String readMethodName;

    /**
     * Constructs a PropertyDescriptor for a property that follows
     * the standard Java convention by having getFoo and setFoo
     * accessor methods.  Thus if the argument name is "fred", it will
     * assume that the writer method is "setFred" and the reader method
     * is "getFred" (or "isFred" for a boolean property).  Note that the
     * property name should start with a lower case character, which will
     * be capitalized in the method names.
     *
     * @param propertyName The programmatic name of the property.
     * @param beanClass The Class object for the target bean.  For
     *          example sun.beans.OurButton.class.
     * @exception IntrospectionException if an exception occurs during
     *              introspection.
     */
    public PropertyDescriptor(String propertyName, Class<?> beanClass)
                throws IntrospectionException {
        this(propertyName, beanClass,
                Introspector.IS_PREFIX + NameGenerator.capitalize(propertyName),
                Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName));
    }
}

1.4 ParameterDescriptor

ParameterDescriptor就是引數描述符

package java.beans;
public class ParameterDescriptor extends FeatureDescriptor {
    /**
     * Public default constructor.
     */
    public ParameterDescriptor() {
    }

    /**
     * Package private dup constructor.
     * This must isolate the new object from any changes to the old object.
     */
    ParameterDescriptor(ParameterDescriptor old) {
        super(old);
    }
}

1.5 Introspector

Introspector將JavaBean中的屬性封裝起來進行操作(讀取)。在程式把一個類當做JavaBean來看,就是呼叫Introspector.getBeanInfo()方法,得到BeanInfo物件。那修改怎麼辦?當然是只能反射了(java.lang.reflect)

構造器 java.lang.reflect.Constructor<T>
方法 java.lang.reflect.Method
欄位 java.lang.reflect.Field
@Test
public void go_getDescriptor() throws IntrospectionException {
    BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
    System.out.println(beanInfo.getBeanDescriptor());
    System.out.println(Arrays.toString(beanInfo.getMethodDescriptors()));
    System.out.println(Arrays.toString(beanInfo.getPropertyDescriptors()));
}

@Test
public void go_setAge() throws IntrospectionException, InvocationTargetException, IllegalAccessException {
    User userInfo = new User();
    String age = "age";
    Object ageValue = 19;
    BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
    PropertyDescriptor[] proDescrtptors = beanInfo.getPropertyDescriptors();
    if (proDescrtptors != null && proDescrtptors.length > 0) {
        for (PropertyDescriptor propDesc : proDescrtptors) {
            if (propDesc.getName().equals(age)) {
                Method methodSetUserName = propDesc.getWriteMethod();//很重要的原則
                methodSetUserName.invoke(userInfo,ageValue);
                Method methodGetUserName = propDesc.getReadMethod();
                System.out.println(methodGetUserName.invoke(userInfo)); //output:19
                break;
            }
        }
    }
}

go_getDescriptor的輸出:

java.beans.BeanDescriptor[name=BeanInfo_test$User; beanClass=class com.example.introspector.BeanInfo_test$User]

[java.beans.MethodDescriptor[name=getClass; method=public final native java.lang.Class java.lang.Object.getClass()], java.beans.MethodDescriptor[name=getUserName; method=public java.lang.String com.example.introspector.BeanInfo_test$User.getUserName()], java.beans.MethodDescriptor[name=setAge; method=public void com.example.introspector.BeanInfo_test$User.setAge(int)], java.beans.MethodDescriptor[name=getAge; method=public int com.example.introspector.BeanInfo_test$User.getAge()], java.beans.MethodDescriptor[name=wait; method=public final void java.lang.Object.wait() throws java.lang.InterruptedException], java.beans.MethodDescriptor[name=notifyAll; method=public final native void java.lang.Object.notifyAll()], java.beans.MethodDescriptor[name=notify; method=public final native void java.lang.Object.notify()], java.beans.MethodDescriptor[name=wait; method=public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException], java.beans.MethodDescriptor[name=setUserName; method=public void com.example.introspector.BeanInfo_test$User.setUserName(java.lang.String)], java.beans.MethodDescriptor[name=hashCode; method=public native int java.lang.Object.hashCode()], java.beans.MethodDescriptor[name=wait; method=public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException], java.beans.MethodDescriptor[name=equals; method=public boolean java.lang.Object.equals(java.lang.Object)], java.beans.MethodDescriptor[name=toString; method=public java.lang.String java.lang.Object.toString()]]

[java.beans.PropertyDescriptor[name=age; propertyType=int; readMethod=public int com.example.introspector.BeanInfo_test$User.getAge(); writeMethod=public void com.example.introspector.BeanInfo_test$User.setAge(int)], java.beans.PropertyDescriptor[name=class; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()], java.beans.PropertyDescriptor[name=userName; propertyType=class java.lang.String; readMethod=public java.lang.String com.example.introspector.BeanInfo_test$User.getUserName(); writeMethod=public void com.example.introspector.BeanInfo_test$User.setUserName(java.lang.String)]]

這裡思考個問題:如果ageValue="19",它就是非int,會報錯(java.lang.IllegalArgumentException: argument type mismatch)該怎麼辦?其實是有解決方案的,繼續往下看

1.6 屬性變化監聽

一般事件觸發流程都是這樣的:傳遞一個字串(Text,它叫法更專業,所以型別的原生形態文字型)型別---》》》把這個Text型別轉換為對應的Java資料型別並賦值---》》》事件發生(不同的屬性對應不同的事件)

PropertyChangeEvent,事件

package java.beans;
public class PropertyChangeEvent extends EventObject {
    private static final long serialVersionUID = 7042693688939648123L;
    /**
     * Constructs a new {@code PropertyChangeEvent}.
     *
     * @param source        the bean that fired the event
     * @param propertyName  the programmatic name of the property that was changed
     * @param oldValue      the old value of the property
     * @param newValue      the new value of the property
     *
     * @throws IllegalArgumentException if {@code source} is {@code null}
     */
    public PropertyChangeEvent(Object source, String propertyName,
                               Object oldValue, Object newValue) {
        super(source);
        this.propertyName = propertyName;
        this.newValue = newValue;
        this.oldValue = oldValue;
    }
}

PropertyChangeListener,監聽器

package java.beans;
public interface PropertyChangeListener extends java.util.EventListener {
    /**
     * This method gets called when a bound property is changed.
     * @param evt A PropertyChangeEvent object describing the event source
     *          and the property that has changed.
     */

    void propertyChange(PropertyChangeEvent evt);
}

PropertyEditor,事件源

package java.beans;
public interface PropertyEditor {
   void setAsText(String text) throws java.lang.IllegalArgumentException;
   Object getValue();
}
public class PropertyEditorSupport implements PropertyEditor {
   public void setAsText(String text) throws java.lang.IllegalArgumentException {
        if (value instanceof String) {
            setValue(text);
            return;
        }
        throw new java.lang.IllegalArgumentException(text);
    }
    public void setValue(Object value) {
        this.value = value;
        firePropertyChange();
    }
    public void firePropertyChange() {
        java.util.Vector<PropertyChangeListener> targets;
        synchronized (this) {
            if (listeners == null) {
                return;
            }
            targets = unsafeClone(listeners);
        }
        // Tell our listeners that "everything" has changed.
        PropertyChangeEvent evt = new PropertyChangeEvent(source, null, null, null);

        for (int i = 0; i < targets.size(); i++) {
            PropertyChangeListener target = targets.elementAt(i);
            target.propertyChange(evt);
        }
    }
}

例項程式碼

Test
public void go_setAgeToListener() throws IntrospectionException {
    User userInfo = new User();
    String age = "age";
    String ageValue = "19";
    BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
    PropertyDescriptor[] proDescrtptors = beanInfo.getPropertyDescriptors();
    for (PropertyDescriptor propDesc : proDescrtptors) {
        if (propDesc.getName().equals(age)) {
            propDesc.setPropertyEditorClass(IntegerEditor.class);//也可以自定義
            PropertyEditor propertyEditor = propDesc.createPropertyEditor(userInfo);
            propertyEditor.addPropertyChangeListener(x -> {
                PropertyEditor source = (PropertyEditor) x.getSource();
                Method methodSetUserName = propDesc.getWriteMethod();
                try {
                    System.out.println("newValue:" + source.getValue());
                    methodSetUserName.invoke(userInfo, source.getValue());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            propertyEditor.setAsText(ageValue);
            break;
        }
    }
}

2. spring bean


2.1 PropertyEditorRegistry

核心屬性修改註冊器,實現類就老厲害了

public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
    private static Class<?> pathClass;
    private static Class<?> zoneIdClass;
    private ConversionService conversionService;
    private boolean defaultEditorsActive = false;
    private boolean configValueEditorsActive = false;
    private Map<Class<?>, PropertyEditor> defaultEditors;
    private Map<Class<?>, PropertyEditor> overriddenDefaultEditors;
    private Map<Class<?>, PropertyEditor> customEditors;
    private Map<String, PropertyEditorRegistrySupport.CustomEditorHolder> customEditorsForPath;
    private Map<Class<?>, PropertyEditor> customEditorCache;

    public PropertyEditorRegistrySupport() {
    }

    public void setConversionService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    public ConversionService getConversionService() {
        return this.conversionService;
    }

    protected void registerDefaultEditors() {
        this.defaultEditorsActive = true;
    }

    public void useConfigValueEditors() {
        this.configValueEditorsActive = true;
    }

    public void overrideDefaultEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
        if(this.overriddenDefaultEditors == null) {
            this.overriddenDefaultEditors = new HashMap();
        }

        this.overriddenDefaultEditors.put(requiredType, propertyEditor);
    }

    public PropertyEditor getDefaultEditor(Class<?> requiredType) {
        if(!this.defaultEditorsActive) {
            return null;
        } else {
            if(this.overriddenDefaultEditors != null) {
                PropertyEditor editor = (PropertyEditor)this.overriddenDefaultEditors.get(requiredType);
                if(editor != null) {
                    return editor;
                }
            }

            if(this.defaultEditors == null) {
                this.createDefaultEditors();
            }

            return (PropertyEditor)this.defaultEditors.get(requiredType);
        }
    }
    //這裡處理xml中常規的轉換
    private void createDefaultEditors() {
        this.defaultEditors = new HashMap(64);
        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());
        if(pathClass != null) {
            this.defaultEditors.put(pathClass, new PathEditor());
        }

        this.defaultEditors.put(Pattern.class, new PatternEditor());
        this.defaultEditors.put(Properties.class, new PropertiesEditor());
        this.defaultEditors.put(Reader.class, new ReaderEditor());
        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());
        }

        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));
        this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
        this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
        this.defaultEditors.put(Character.TYPE, new CharacterEditor(false));
        this.defaultEditors.put(Character.class, new CharacterEditor(true));
        this.defaultEditors.put(Boolean.TYPE, new CustomBooleanEditor(false));
        this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
        this.defaultEditors.put(Byte.TYPE, new CustomNumberEditor(Byte.class, false));
        this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
        this.defaultEditors.put(Short.TYPE, new CustomNumberEditor(Short.class, false));
        this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
        this.defaultEditors.put(Integer.TYPE, new CustomNumberEditor(Integer.class, false));
        this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
        this.defaultEditors.put(Long.TYPE, new CustomNumberEditor(Long.class, false));
        this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
        this.defaultEditors.put(Float.TYPE, new CustomNumberEditor(Float.class, false));
        this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
        this.defaultEditors.put(Double.TYPE, 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));
        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);
        }
    }
}

2.2 PropertyEditorRegistrar

它是PropertyEditorRegistry中的defaultEditors的功能拓展

//它本身是null實現,實現類BeanWrapperFieldSetMapper是真正的實現(向PropertyEditorRegistry中新增DataBinder到customEditors,DataBinder就老厲害了(想想springmvc的@RequestBody就懂了))
public class DefaultPropertyEditorRegistrar implements PropertyEditorRegistrar {
	private Map<Class<?>, PropertyEditor> customEditors;
	/**
	 * Register the custom editors with the given registry.
	 * 
	 * @see org.springframework.beans.PropertyEditorRegistrar#registerCustomEditors(org.springframework.beans.PropertyEditorRegistry)
	 */
    @Override
	public void registerCustomEditors(PropertyEditorRegistry registry) {
		if (this.customEditors != null) {
			for (Entry<Class<?>, PropertyEditor> entry : customEditors.entrySet()) {
				registry.registerCustomEditor(entry.getKey(), entry.getValue());
			}
		}
	}
	/**
	 * Specify the {@link PropertyEditor custom editors} to register.
	 * 
	 * 
	 * @param customEditors a map of Class to PropertyEditor (or class name to
	 * PropertyEditor).
	 * @see CustomEditorConfigurer#setCustomEditors(Map)
	 */
	public void setCustomEditors(Map<? extends Object, ? extends PropertyEditor> customEditors) {
		this.customEditors = new HashMap<Class<?>, PropertyEditor>();
		for (Entry<? extends Object, ? extends PropertyEditor> entry : customEditors.entrySet()) {
			Object key = entry.getKey();
			Class<?> requiredType = null;
			if (key instanceof Class<?>) {
				requiredType = (Class<?>) key;
			}
			else if (key instanceof String) {
				String className = (String) key;
				requiredType = ClassUtils.resolveClassName(className, getClass().getClassLoader());
			}
			else {
				throw new IllegalArgumentException("Invalid key [" + key
						+ "] for custom editor: needs to be Class or String.");
			}
			PropertyEditor value = entry.getValue();
			this.customEditors.put(requiredType, value);
		}
	}

}
//處理xml中Resource、URL、File...、向PropertyEditorRegistry中新增registry.registerCustomEditor或overrideDefaultEditor(requiredType, editor)
public class ResourceEditorRegistrar implements PropertyEditorRegistrar {

	private static Class<?> pathClass;

	static {
		try {
			pathClass = ClassUtils.forName("java.nio.file.Path", ResourceEditorRegistrar.class.getClassLoader());
		}
		catch (ClassNotFoundException ex) {
			// Java 7 Path class not available
			pathClass = null;
		}
	}
	private final PropertyResolver propertyResolver;
	private final ResourceLoader resourceLoader;
	/**
	 * Create a new ResourceEditorRegistrar for the given {@link ResourceLoader}
	 * and {@link PropertyResolver}.
	 * @param resourceLoader the ResourceLoader (or ResourcePatternResolver)
	 * to create editors for (usually an ApplicationContext)
	 * @param propertyResolver the PropertyResolver (usually an Environment)
	 * @see org.springframework.core.env.Environment
	 * @see org.springframework.core.io.support.ResourcePatternResolver
	 * @see org.springframework.context.ApplicationContext
	 */
	public ResourceEditorRegistrar(ResourceLoader resourceLoader, PropertyResolver propertyResolver) {
		this.resourceLoader = resourceLoader;
		this.propertyResolver = propertyResolver;
	}


	/**
	 * Populate the given {@code registry} with the following resource editors:
	 * ResourceEditor, InputStreamEditor, InputSourceEditor, FileEditor, URLEditor,
	 * URIEditor, ClassEditor, ClassArrayEditor.
	 */
	@Override
	public void registerCustomEditors(PropertyEditorRegistry registry) {
		ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
		doRegisterEditor(registry, Resource.class, baseEditor);
		doRegisterEditor(registry, ContextResource.class, baseEditor);
		doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
		doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
		doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
		if (pathClass != null) {
			doRegisterEditor(registry, pathClass, new PathEditor(baseEditor));
		}
		doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
		doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));

		ClassLoader classLoader = this.resourceLoader.getClassLoader();
		doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
		doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
		doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));

		if (this.resourceLoader instanceof ResourcePatternResolver) {
			doRegisterEditor(registry, Resource[].class,
					new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
		}
	}

	/**
	 * Override default editor, if possible (since that's what we really mean to do here);
	 * otherwise register as a custom editor.
	 */
	private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
		if (registry instanceof PropertyEditorRegistrySupport) {
			((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
		}
		else {
			registry.registerCustomEditor(requiredType, editor);
		}
	}

}

2.3 CustomEditorConfigurer

可以自定義PropertyEditorRegistry、PropertyEditor,它其實是一個BeanFactoryPostProcessor

public class CustomEditorConfigurer implements BeanFactoryPostProcessor, Ordered {

	protected final Log logger = LogFactory.getLog(getClass());

	private int order = Ordered.LOWEST_PRECEDENCE;  // default: same as non-Ordered

	private PropertyEditorRegistrar[] propertyEditorRegistrars;

	private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;


	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public int getOrder() {
		return this.order;
	}
	public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) {
		this.propertyEditorRegistrars = propertyEditorRegistrars;
	}
	public void setCustomEditors(Map<Class<?>, Class<? extends PropertyEditor>> customEditors) {
		this.customEditors = customEditors;
	}
    
    //beanFactory中新增PropertyEditorRegistrar和PropertyEditor
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		if (this.propertyEditorRegistrars != null) {
			for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
				beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);
			}
		}
		if (this.customEditors != null) {
			for (Map.Entry<Class<?>, Class<? extends PropertyEditor>> entry : this.customEditors.entrySet()) {
				Class<?> requiredType = entry.getKey();
				Class<? extends PropertyEditor> propertyEditorClass = entry.getValue();
				beanFactory.registerCustomEditor(requiredType, propertyEditorClass);
			}
		}
	}
}

總結,springBean其實是整合拓展了javaBean的內省解決方案,但在它的基礎上做了增強。