/** * The central interface of Spring's low-level JavaBeans infrastructure. * * <p>Typically not used directly but rather implicitly via a * {@link org.springframework.beans.factory.BeanFactory} or a * {@link org.springframework.validation.DataBinder}. * * <p>Provides operations to analyze and manipulate standard JavaBeans: * the ability to get and set property values (individually or in bulk), * get property descriptors, and query the readability/writability of properties. * * <p>This interface supports <b>nested properties</b> enabling the setting * of properties on subproperties to an unlimited depth. * * <p>A BeanWrapper's default for the "extractOldValueForEditor" setting * is "false", to avoid side effects caused by getter method invocations. * Turn this to "true" to expose present property values to custom editors. * */ publicinterfaceBeanWrapperextendsConfigurablePropertyAccessor{ ... }
/** * Default {@link BeanWrapper} implementation that should be sufficient * for all typical use cases. Caches introspection results for efficiency. * ... ... /** * Create a new BeanWrapperImpl for the given object. * @param object object wrapped by this BeanWrapper */ publicBeanWrapperImpl(Object object){ super(object); }
顾名思义,提供了对Bean的Property的set和get的方法,其实还有很丰富的方法,比如批量set和get属性,获取一个属性的读写权限信息,获取某个属性的类型或者类型描述(TypeDescriptor:Context about a type to convert from or to.)等方法。
/** * Cached introspections results for this object, to prevent encountering * the cost of JavaBeans introspection every time. */ @Nullable private CachedIntrospectionResults cachedIntrospectionResults;
这个对象里面保存了一个static Map,缓存了所有的Class自省的结果:
1 2 3 4 5 6 7 8 9 10 11
publicfinalclassCachedIntrospectionResults{ ... /** * Map keyed by Class containing CachedIntrospectionResults, strongly held. * This variant is being used for cache-safe bean classes. */ staticfinal ConcurrentMap<Class<?>, CachedIntrospectionResults> strongClassCache = new ConcurrentHashMap<>(64); ... }
每个CachedIntrospectionResults对象里面又有以下属性:
1 2 3 4 5 6 7 8
/** The BeanInfo object for the introspected bean class. */ privatefinal BeanInfo beanInfo;
/** PropertyDescriptor objects keyed by property name String. */ privatefinal Map<String, PropertyDescriptor> propertyDescriptorCache;
... /** * Actually register the default editors for this registry instance. */ privatevoidcreateDefaultEditors(){ this.defaultEditors = new HashMap<>(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(Path.class, 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()); this.defaultEditors.put(ZoneId.class, 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); } } ... @Override publicvoidregisterCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor){ registerCustomEditor(requiredType, null, propertyEditor); } ... }
/** * Set the class to introspect. * Needs to be called when the target object changes. * @param clazz the class to introspect */ protectedvoidsetIntrospectionClass(Class<?> clazz){ if (this.cachedIntrospectionResults != null && this.cachedIntrospectionResults.getBeanClass() != clazz) { this.cachedIntrospectionResults = null; } }