BeanWrapper(二)

简介: 其实这篇文章只是单纯的去了解关于 PropertyEditor 和 ConversionServer 的知识、并没有从源码详细说 Spring 怎么怎么去使用它们、这个可能放到以后的文章。这篇文章单纯是补全这个主题的基础知识、为后面继续看 Spring 的代码进行铺垫。

TypeConverter


Spring 提供多类型转换器。子类实现该接口的同时一般也会实现 PropertyEditorRegistry 接口,当然这不是必须的。

因为类型转换器的实现是基于 PropertyEditor 的、而 PropertyEditor 是线程不安全的、所以 TypeConverter 也是线程不安全的。

/**
 * Interface that defines type conversion methods. Typically (but not necessarily)
 * implemented in conjunction with the {@link PropertyEditorRegistry} interface.
 */
public interface TypeConverter {
   @Nullable
   <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException;
   @Nullable
   <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
         @Nullable MethodParameter methodParam) throws TypeMismatchException;
   @Nullable
   <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field)
         throws TypeMismatchException;
   @Nullable
   default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
         @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
      throw new UnsupportedOperationException("TypeDescriptor resolution not supported");
   }
}
复制代码


TypeConverterSupport

这个基于 JDK PropertyEditor 的体系的命名方式都是 xxxSupport,这个抽象类不单实现了 TypeConverter 而且继承 PropertyEditorRegistrySupport。

这个类主要是作为 BeanWrapperImpl 的基类。

网络异常,图片无法展示
|

该抽象类中存在一个成员变量 TypeConverterDelegate typeConverterDelegate; 真正的转换工作是在它里面进行操作的。这个后续再看它里面的实现。


SimpleTypeConverter

/**
 * Simple implementation of the {@link TypeConverter} interface that does not operate on
 * a specific target object. This is an alternative to using a full-blown BeanWrapperImpl
 * instance for arbitrary type conversion needs, while using the very same conversion
 * algorithm (including delegation to {@link java.beans.PropertyEditor} and
 * {@link org.springframework.core.convert.ConversionService}) underneath.
 *
 * <p><b>Note:</b> Due to its reliance on {@link java.beans.PropertyEditor PropertyEditors},
 * SimpleTypeConverter is <em>not</em> thread-safe. Use a separate instance for each thread.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see BeanWrapperImpl
 */
public class SimpleTypeConverter extends TypeConverterSupport {
   public SimpleTypeConverter() {
      this.typeConverterDelegate = new TypeConverterDelegate(this);
      registerDefaultEditors();
   }
}
复制代码


简单实现 TypeConverter 接口、跟 BeanWrapperImpl 的逻辑是一样的。同样它也是非线程安全的。

网络异常,图片无法展示
|

public TypeConverter getTypeConverter() {
   TypeConverter customConverter = getCustomTypeConverter();
   if (customConverter != null) {
      return customConverter;
   }
   else {
      // Build default TypeConverter, registering custom editors.
      SimpleTypeConverter typeConverter = new SimpleTypeConverter();
      typeConverter.setConversionService(getConversionService());
      registerCustomEditors(typeConverter);
      return typeConverter;
   }
}
复制代码

我们在获取 bean 的时候、如果有传入类型、并且在 bean 的类型和入参的不一致的时候、那么就会尝试进行转换。


PropertyAccessor


网络异常,图片无法展示
|


观其名知其意

网络异常,图片无法展示
|


ConfigurablePropertyAccessor

public interface ConfigurablePropertyAccessor 
  extends PropertyAccessor, PropertyEditorRegistry, TypeConverter {
  .....
}
复制代码

继承 PropertyAccessor, PropertyEditorRegistry, TypeConverter 。


AbstractPropertyAccessor

实现了所有转换的方法、真正的属性访问的方法留给子类实现

public abstract class AbstractPropertyAccessor extends TypeConverterSupport implements ConfigurablePropertyAccessor {
}
复制代码


AbstractNestablePropertyAccessor

提供将对应的集合/数组的值给到目标对象的集合/数组的字段中。

public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyAccessor 
复制代码


BeanWrapperImpl


public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper {
复制代码


最终 BeanWrapperImpl 继承了 AbstractNestablePropertyAccessor ,所以它具有了访问属性以及进行相应的类型的能力。

* NOTE: As of Spring 2.5, this is - for almost all purposes - an
* internal class. It is just public in order to allow for access from
* other framework packages. For standard application access purposes, use the
* {@link PropertyAccessorFactory#forBeanPropertyAccess} factory method instead.
复制代码


虽然我们在程序中很少直接使用 BeanWrapper 、一般都是使用 BeanUtils 或者 BeanCopier

public class AppTest {
    @Test
    public void shouldAnswerWithTrue() {
        Staff staff = new Staff();
        BeanWrapper staffWrapper = new BeanWrapperImpl(staff);
        //设置属性
        staffWrapper.setPropertyValue("id", "1001");
        //设置属性
        staffWrapper.setPropertyValue(new PropertyValue("name", "小王"));
        //设置属性
        staffWrapper.setPropertyValue("hobbies[0]", "羽毛球");
        staffWrapper.setPropertyValue("hobbies[1]", "篮球");
        System.out.println("================");
        //获取属性
        Object id = staffWrapper.getPropertyValue("id");
        System.out.println("id="+id);
        //获取属性
        Object name = staffWrapper.getPropertyValue("name");
        System.out.println("name="+name);
        //获取属性
        Object hobbies = staffWrapper.getPropertyValue("hobbies");
        System.out.println("hobbies="+hobbies);
        //获取属性
        Object hobbies_0 = staffWrapper.getPropertyValue("hobbies[0]");
        System.out.println("hobbies[0]="+hobbies_0);
        System.out.println("================");
        System.out.println("staff="+staff.toString());
        System.out.println("================");
        Company company = new Company();
        BeanWrapper companyWrapper = new BeanWrapperImpl(company);
        companyWrapper.setPropertyValue("staffs[" + staff.getId() + "]", staff);
        System.out.println(company.getStaffs().get(staff.getId()));
    }
}
class Staff {
    private String id;
    private String name;
    private List<String> hobbies = new ArrayList<>();
    public void setId(String id) {
    System.out.println("setId 方法被调用");
    this.id = id;
}
public void setName(String name) {
    System.out.println("setName 方法被调用");
    this.name = name;
}
public String getId() {
    System.out.println("getId 方法被调用");
    return id;
}
public String getName() {
    System.out.println("getName 方法被调用");
    return name;
}
public List<String> getHobbies() {
    System.out.println("getHobbies 方法被调用");
    return hobbies;
}
public void setHobbies(List<String> hobbies) {
    System.out.println("getHobbies 方法被调用");
    this.hobbies = hobbies;
}
@Override
public String toString() {
    return "Staff{" +
            "id='" + id + '\'' +
            ", name='" + name + '\'' +
            ", hobbies=" + Arrays.toString(hobbies.toArray()) +
            '}';
}
}
class  Company{
    private Map<String, Staff> staffs = new HashMap<>();
    public Map<String, Staff> getStaffs() {
        return staffs;
    }
    public void setStaffs(Map<String, Staff> staffs) {
        this.staffs = staffs;
    }
}
复制代码


网上复制的例子

blog.csdn.net/hong10086/a…

setId 方法被调用
setName 方法被调用
getHobbies 方法被调用
getHobbies 方法被调用
================
getId 方法被调用
id=1001
getName 方法被调用
name=小王
getHobbies 方法被调用
hobbies=[羽毛球, 篮球]
getHobbies 方法被调用
hobbies[0]=羽毛球
================
staff=Staff{id='1001', name='小王', hobbies=[羽毛球, 篮球]}
================
getId 方法被调用
getId 方法被调用
Staff{id='1001', name='小王', hobbies=[羽毛球, 篮球]}
复制代码
目录
相关文章
|
1月前
|
XML JavaScript Java
BeanFactory 和 FactoryBean的区别
本文介绍了Spring框架中的`BeanFactory`和`FactoryBean`。`BeanFactory`是Spring的核心接口,用于管理Bean的创建、配置及依赖注入。其实现包括`DefaultListableBeanFactory`和已废弃的`XmlBeanFactory`。`FactoryBean`则用于动态创建Bean实例,支持懒加载及AOP代理创建。文章还通过示例展示了如何实现一个`FactoryBean`,并通过测试验证其功能。最后附上了作者信息及版权声明。
BeanFactory 和 FactoryBean的区别
|
6月前
|
设计模式 Java Spring
BeanFactory与FactoryBean的区别
BeanFactory与FactoryBean的区别
|
XML Java 数据库连接
FactoryBean的使用~
FactoryBean的使用~
|
Java 开发者 Spring
BeanFactory和FactoryBean
BeanFactory和FactoryBean
87 0
|
Java Spring 容器
|
安全 Java Spring
BeanWrapper(三)
其实这篇文章只是单纯的去了解关于 PropertyEditor 和 ConversionServer 的知识、并没有从源码详细说 Spring 怎么怎么去使用它们、这个可能放到以后的文章。这篇文章单纯是补全这个主题的基础知识、为后面继续看 Spring 的代码进行铺垫。
139 0
|
安全 Java Spring
BeanWrapper(一)
其实这篇文章只是单纯的去了解关于 PropertyEditor 和 ConversionServer 的知识、并没有从源码详细说 Spring 怎么怎么去使用它们、这个可能放到以后的文章。这篇文章单纯是补全这个主题的基础知识、为后面继续看 Spring 的代码进行铺垫。
145 0
|
搜索推荐 Java API
3. 搞定收工,PropertyEditor就到这(下)
3. 搞定收工,PropertyEditor就到这(下)
3. 搞定收工,PropertyEditor就到这(下)
|
缓存 Java API
3. 搞定收工,PropertyEditor就到这(上)
3. 搞定收工,PropertyEditor就到这(上)
3. 搞定收工,PropertyEditor就到这(上)
|
XML JSON Java
Spring源码解析 - FactoryBean&&BeanFactory(上)
Spring源码解析 - FactoryBean&&BeanFactory
125 0
Spring源码解析 - FactoryBean&&BeanFactory(上)