spring源码分析

     在spring源码中,在很多地方都会出现PropertyEditor,那么属性编辑器用来干什么的呢?属性编辑器主要应用在以下两个方面:

  • 使用PropertyEditors设置Bean属性。当你在XML文件中声明的bean的属性类型为java.lang.String时,Spring将在容器初始化该bean时使用ClassEditor将String解析成Class对象(如果setter方法需要一个Class参数的话)。这么说有点难以理解,请看下面这个代码片段:

    <bean class="com.github.thinwonton.spring.source.analysis.propertyeditor.ClassHolder"> <property name="clazz" value="com.github.thinwonton.spring.source.analysis.propertyeditor.Order"/> </bean>

    public class ClassHolder { private Class<?> clazz;

    1public Class<?> getClazz() { 2 return clazz; 3} 4 5public void setClazz(Class<?> clazz) { 6 this.clazz = clazz; 7}

    }

  • 在Spring MVC架构中使用各种PropertyEditors来解析HTTP请求中的参数。

  Spring提供了许多内建的PropertyEditors可以简化我们的工作,它们都位于org.springframework.beans.PropertyEditors包内。它们中的大多数已经默认在BeanWrapperImpl的实现类中注册好了。作为可配置的选项,我们也可以注册自己的属性编辑器实现去覆盖那些默认编辑器。

    由于PropertyEditor是spring源码分析的基础,于是决定研究一下PropertyEditor。在探索的过程中,发现了下面这篇分析PropertyEditor比较好的文章,就不想再造轮子了。后面还会写一篇关于怎么 在spring中使用自定义PropertyEditor的文章(https://my.oschina.net/thinwonton/blog/1492107),用于补充下面的内容。

=============================================================

    在spring配置文件或配置类里,通过字符串为Bean各种属性提供设置值:不管是double类型还是int类型,在配置文件中都对应字符串类型。BeanWrapper填充Bean属性时如何将这个字面值转换为对应的double或int等内部类型呢?我们可以隐约地感觉到一定有一个转换器在其中起作用,这个转换器就是属性编辑器。

1、PropertyEditor

    java.beans.PropertyEditor是属性编辑器的接口,它规定了将外部设置值转换为内部JavaBean属性值的转换接口方法。PropertyEditor主要的接口方法说明如下: 

  • Object getValue():返回属性的当前值。基本类型被封装成对应的封装类实例; 
  •  void setValue(Object newValue):设置属性的值,基本类型以封装类传入; 
  • String getAsText():将属性对象用一个字符串表示,以便外部的属性编辑器能以可视化的方式显示。缺省返回null,表示该属性不能以字符串表示; 
  •  void setAsText(String text):用一个字符串去更新属性的内部值,这个字符串一般从外部属性编辑器传入; 
  •  String[] getTags():返回表示有效属性值的字符串数组(如boolean属性对应的有效Tag为true和false),以便属性编辑器能以下拉框的方式显示出来。缺省返回null,表示属性没有匹配的字符值有限集合; 
  •  String getJavaInitializationString():为属性提供一个表示初始值的字符串,属性编辑器以此值作为属性的默认值。

    可以看出PropertyEditor接口方法是内部属性值和外部设置值的沟通桥梁。此外,我们可以很容易地发现该接口的很多方法是专为IDE中的可视化属性编辑器提供的:如getTags()、getJavaInitializationString()以及另外一些我们未此介绍的接口方法。

PropertyEditorSupport

    Java为PropertyEditor提供了一个方便类:PropertyEditorSupport,该类实现了PropertyEditor接口并提供默认实现,一般情况下,用户可以通过扩展这个方便类设计自己的属性编辑器。

spring中的属性编辑器

    Spring大部分默认属性编辑器都直接扩展于java.beans.PropertyEditorSupport类,用户也可以通过扩展PropertyEditorSupport实现自己的属性编辑器。比起用于IDE环境的属性编辑器来说,Spring环境下使用的属性编辑器的功能非常单一:仅需要将配置文件中字面值转换为属性类型的对象即可,并不需要提供UI界面,因此仅需要简单覆盖PropertyEditorSupport的setAsText()方法就可以了。 

举个栗子:

实现 UUIDEditor 
 

1public class UUIDEditor extends PropertyEditorSupport { 2 3 @Override 4 public void setAsText(String text) throws IllegalArgumentException { 5 if (StringUtils.hasText(text)) { 6 setValue(UUID.fromString(text)); 7 } 8 else { 9 setValue(null); 10 } 11 } 12 13 @Override 14 public String getAsText() { 15 UUID value = (UUID) getValue(); 16 return (value != null ? value.toString() : ""); 17 } 18 19} 20 21public static void main(String[] args) throws ClassNotFoundException, IOException { 22 23 //UUID对象转化为字符串 24 UUIDEditor editor=new UUIDEditor(); 25 editor.setValue(UUID.randomUUID()); 26 System.out.println(editor.getAsText());//c2878055-fb49-4559-a7db-c60fc3ebee79 27 28 //字符串转化为UUID 29 UUIDEditor editor_2=new UUIDEditor(); 30 editor_2.setAsText("2-1-1-2-3"); 31 System.out.println(editor_2.getAsText());//00000002-0001-0001-0002-000000000003 32 System.out.println(editor_2.getValue().getClass());//class java.util.UUID 33 34}

2、PropertyEditorRegistry

这个接口可以注册和保存属性编辑器

1public interface PropertyEditorRegistry { 2 3 void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor); 4 5 void registerCustomEditor(Class<?> requiredType, String propertyPath, PropertyEditor propertyEditor); 6 7 PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath); 8 9}

PropertyEditorRegistrySupport

PropertyEditorRegistrySupport是PropertyEditorRegistry 默认实现类 
PropertyEditorRegistrySupport中有两个用于保存属性编辑器的Map类型变量:

1private Map<Class<?>, PropertyEditor> defaultEditors; 2 3private Map<Class<?>, PropertyEditor> customEditors;

PropertyEditorRegistrySupport通过以下的代码定义默认属性编辑器:

1 private void createDefaultEditors() { 2 this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64); 3 4 // Simple editors, without parameterization capabilities. 5 // The JDK does not contain a default editor for any of these target types. 6 this.defaultEditors.put(Charset.class, new CharsetEditor()); 7 this.defaultEditors.put(Class.class, new ClassEditor()); 8 this.defaultEditors.put(Class[].class, new ClassArrayEditor()); 9 this.defaultEditors.put(Currency.class, new CurrencyEditor()); 10 this.defaultEditors.put(File.class, new FileEditor()); 11 this.defaultEditors.put(InputStream.class, new InputStreamEditor()); 12 this.defaultEditors.put(InputSource.class, new InputSourceEditor()); 13 this.defaultEditors.put(Locale.class, new LocaleEditor()); 14 this.defaultEditors.put(Pattern.class, new PatternEditor()); 15 this.defaultEditors.put(Properties.class, new PropertiesEditor()); 16 this.defaultEditors.put(Reader.class, new ReaderEditor()); 17 this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor()); 18 this.defaultEditors.put(TimeZone.class, new TimeZoneEditor()); 19 this.defaultEditors.put(URI.class, new URIEditor()); 20 this.defaultEditors.put(URL.class, new URLEditor()); 21 this.defaultEditors.put(UUID.class, new UUIDEditor()); 22 if (zoneIdClass != null) { 23 this.defaultEditors.put(zoneIdClass, new ZoneIdEditor()); 24 } 25 26 // Default instances of collection editors. 27 // Can be overridden by registering custom instances of those as custom editors. 28 this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class)); 29 this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class)); 30 this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class)); 31 this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class)); 32 this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class)); 33 34 // Default editors for primitive arrays. 35 this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor()); 36 this.defaultEditors.put(char[].class, new CharArrayPropertyEditor()); 37 38 // The JDK does not contain a default editor for char! 39 this.defaultEditors.put(char.class, new CharacterEditor(false)); 40 this.defaultEditors.put(Character.class, new CharacterEditor(true)); 41 42 // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor. 43 this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false)); 44 this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true)); 45 46 // The JDK does not contain default editors for number wrapper types! 47 // Override JDK primitive number editors with our own CustomNumberEditor. 48 this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false)); 49 this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true)); 50 this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false)); 51 this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true)); 52 this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false)); 53 this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true)); 54 this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false)); 55 this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true)); 56 this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false)); 57 this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true)); 58 this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false)); 59 this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true)); 60 this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true)); 61 this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true)); 62 63 // Only register config value editors if explicitly requested. 64 if (this.configValueEditorsActive) { 65 StringArrayPropertyEditor sae = new StringArrayPropertyEditor(); 66 this.defaultEditors.put(String[].class, sae); 67 this.defaultEditors.put(short[].class, sae); 68 this.defaultEditors.put(int[].class, sae); 69 this.defaultEditors.put(long[].class, sae); 70 } 71 }
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )