唯一子类(BeanWrapperImpl)
继承关系
结合我们之前对接口的分析以及上面这张UML图,我们可以知道BeanWrapperImpl主要实现了一下几个功能
1.对Bean进行包装
2.对Bean的属性进行访问以及设置
3.在操作属性的过程中,必然涉及到类型转换,所以还有类型转换的功能
Java中的内置机制
在详细了解BeanWrapperImpl前,必须要了解java中的一个机制:内省
核心概念
首先可以先了解下JavaBean的概念:一种特殊的类,主要用于传递数据信息。这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”。
因此JavaBean都有如下几个特征:
1.属性都是私有的;
2.有无参的public构造方法;
3.对私有属性根据需要提供公有的getXxx方法以及setXxx方法;
4.getters必须有返回值没有方法参数;setter值没有返回值,有方法参数;
符合这些特征的类,被称为JavaBean;JDK中提供了一套API用来访问某个属性的getter/setter方法,这些API存放在java.beans中,这就是内省(Introspector)。
内省和反射的区别:
反射:Java反射机制是在运行中,对任意一个类,能够获取得到这个类的所有属性和方法;它针对的是任意类
内省(Introspector):是Java语言对JavaBean类属性、事件的处理方法
1.反射可以操作各种类的属性,而内省只是通过反射来操作JavaBean的属性
2.内省设置属性值肯定会调用setter方法,反射可以不用(反射可直接操作属性Field)
3.反射就像照镜子,然后能看到.class的所有,是客观的事实。内省更像主观的判断:比如看到getName(),内省就会认为这个类中有name字段,但事实上并不一定会有name;通过内省可以获取bean的getter/setter
使用示例
public class Main { public static void main(String[] args) throws Exception{ BeanInfo beanInfo = Introspector.getBeanInfo(People.class); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { System.out.print(propertyDescriptor.getName()+" "); } } // 程序输出:age class name // 为什么会输出class呢?前文中有提到,“看到getName(),内省就会认为这个类中有name字段,但事实上并不一定会有name”,我们知道每个对象都会有getClass方法,所以使用内省时,默认就认为它具有class这个字段 } class People{ String name; int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
源码分析
// 这个类我只保留一些关键的代码,其余的琐碎代码都不看了 public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper { // 缓存内省的结果,BeanWrapperImpl就是通过这个对象来完成对包装的Bean的属性的控制 @Nullable private CachedIntrospectionResults cachedIntrospectionResults; ...... public void setBeanInstance(Object object) { this.wrappedObject = object; this.rootObject = object; // 实际进行类型转换的对象:typeConverterDelegate this.typeConverterDelegate = new TypeConverterDelegate(this, this.wrappedObject); setIntrospectionClass(object.getClass()); } ...... // 最终调用的就是CachedIntrospectionResults的forClass方法进行内省并缓存,底层调用的就是java的内省机制 private CachedIntrospectionResults getCachedIntrospectionResults() { if (this.cachedIntrospectionResults == null) { this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(getWrappedClass()); } return this.cachedIntrospectionResults; } ....... // 最终进行类型转换的方法 private Object convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue, @Nullable Class<?> requiredType, @Nullable TypeDescriptor td) throws TypeMismatchException { Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate"); try { // 可以看到,最后就是调用typeConverterDelegate来进行类型转换 return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td); } ...... } }
父类作用分析
对于接口,我们已经分析过了,这里就不再赘述了,我们重点看下BeanWrapperImpl继承的几个父类
PropertyEditorRegistrySupport
这个类最大的作用在于管理PropertyEditor,添加了很多的默认的PropertyEditor。在PropertyEditorRegistry的基础上做了进一步的扩展,提供的还是属性编辑器注册的功能。
TypeConverterSupport
public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter { @Nullable TypeConverterDelegate typeConverterDelegate; ...... }
这个接口实现了TypeConverter,所以它具有类型转换的能力,而它这种能力的实现,依赖于它所持有的一个TypeConverterDelegate。
AbstractPropertyAccessor
public abstract class AbstractPropertyAccessor extends TypeConverterSupport implements ConfigurablePropertyAccessor { // 省略部分代码...... @Override public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) throws BeansException { List<PropertyAccessException> propertyAccessExceptions = null; List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ? ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues())); for (PropertyValue pv : propertyValues) { try { setPropertyValue(pv); } // .... } } @Override @Nullable public abstract Object getPropertyValue(String propertyName) throws BeansException; @Override public abstract void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException; }
核心的代码其实就是这些,这个类继承了TypeConverterSupport,所以它具备了类型转换的能力。同时它也是一个属性访问器,但是它只是实现了批量设置属性的方法,真正的setPropertyValue还是留待子类实现。可以看到,到这个类为止,还没有将属性的设置跟类型转换的能力结合起来。
AbstractNestablePropertyAccessor
这个类开始真正的将属性访问跟类型转换结合到一起,它真正的实现了setPropertyValue,并在设置属性的时候会进行类型的转换,具体代码就不看了,非常繁杂,但是整体不难。
上面我们多次提到了类型转换,但是还没有真正看到类型转换的逻辑,因为上面类最终将类型转换的逻辑委托给了TypeConverterDelegate。接下来我们看看,类型转换到底是怎么完成。