当前位置: 移动技术网 > IT编程>开发语言>Java > springboot-ObjectToObjectConverter发现

springboot-ObjectToObjectConverter发现

2020年07月17日  | 移动技术网IT编程  | 我要评论

springboot属性绑定

在springboot现在如日中天的时候,虽然很多人都在用它,但是有些伙伴可能并不知道它的神秘之处,或许或多或少有一些疑问?

比如:

  1. 跟着官网愉快的在application配置文件配置了一堆堆文本,怎么变成转换到java类的各个属性的呢?

gateway引发今天的思考

最近笔者在学习gateway的路由predicate、filters的配置,就是在思考怎么转换成对象RouteDefinition,所以今天特地深入研究下。

思考:

  1. 首先RouteDefinition也是属于GatewayProperties的一个属性,所以我们配置的一大堆东西肯定是被映射到GatewayProperties上的
  2. 大家都知道,GatewayProperties是一个@ConfigurationProperties(“spring.cloud.gateway”),即有一个ConfigurationPropertiesBindingPostProcessor后置处理器来处理,这里先不做详细介绍,先讲重点
  3. 我们知道在spring中,属性绑定有两个重要组件PropertyEditor和Converter(两个作用都是将一个值,转换为另一个值)
  4. 经过我仔细一层层查找,发现ConfigurationPropertiesBindingPostProcessor也同样包括PropertyEditor和Converter,这样真相大白了
    (想发散的同学,可以根据ConfigurationPropertiesBinder类去先熟悉熟悉)

ConfigurationPropertiesBinder

private Binder getBinder() {
   	if (this.binder == null) {
   	    //在这里发现,这个binder对象,拥有ConversionService(这个对象拥有我们所需要的的List<Converter>集合)
   		this.binder = new Binder(getConfigurationPropertySources(), getPropertySourcesPlaceholdersResolver(),
   				getConversionService(), getPropertyEditorInitializer(), null,
   				ConfigurationPropertiesBindConstructorProvider.INSTANCE);
   	}
   	return this.binder;
}
  • 有意思的是,在springboot中,这个ConversionService接口对象(实际对象是ApplicationConversionService类)是一个,用双层检查锁DCL(double check lock)来实现的线程安全的单例
	//ApplicationConversionService类中
	public static ConversionService getSharedInstance() {
   	ApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;
   	if (sharedInstance == null) {
   		synchronized (ApplicationConversionService.class) {
   			sharedInstance = ApplicationConversionService.sharedInstance;
   			if (sharedInstance == null) {
   				sharedInstance = new ApplicationConversionService();
   				ApplicationConversionService.sharedInstance = sharedInstance;
   			}
   		}
   	}
   	return sharedInstance;
   }
  • 更有意思的是,这个类实际上在springboot的SpringApplication启动在configureEnvironment这一步的时候,就已经默认加载了
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
       //这个默认是true
		if (this.addConversionService) {
		    //ApplicationConversionService的单例加载
			ConversionService conversionService = ApplicationConversionService.getSharedInstance();
			environment.setConversionService((ConfigurableConversionService) conversionService);
		}
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

ObjectToObjectConverter

  • 在ApplicationConversionService类初始化的时候,就会添加很多很多Converter,在#addDefaultConverters方法中我们就可以找到今天的主角。

  • 通过看代码和代码注释,可以得出ObjectToObjectConverter类进行转换有几个关注方法。

代码可以各位去看,我就不贴出来了,只是根据具体例子来演示。这个我们先定义好源类型和目标类型(想要转换的类型)

源类型SourceClass => String.class (因为我们配置的东西大多都是字符串)
源的值 SourceValue => “abc”
目标类型TargetClass => People.class (假设我们有一个People对象)

  1. determineToMethod

指的是:在SourceClass类中查找to${TargetClass.simpleClassName}的方法。

在这里的例子中,也就是在String类中,查找toPeople的方法,如果找不到,则跳过
public People toPeople(String source){}

不过我们也不可能在String类中定义方法,所以这个determineToMethod 有判断,只要任何一方为String类型,就直接返回null

if (String.class == targetClass || String.class == sourceClass) {
			// Do not accept a toString() method or any to methods on String itself
			return null;
		}
  1. determineFactoryMethod

指的是: 在TargetClass中查找静态方法,valueOf、 of 、from方法

在这里的例子中,就是在People中查找如下三种方法,进行工厂方法转换
public static People valueOf (String source){}
public static People of  (String source){}
public static People from(String source){}
  • 如果找不到valueOf、of 、from三种方法,则最后一步,根据构造函数转换
  1. determineFactoryConstructor

指的是: 根据构造函数转换对象

也就是在People类中,查找source的构造函数,进行转换
public People(String source){} 

Gateway验证

  1. 通过ObjectToObjectConverter我们知道了,springboot可以通过静态方法、构造方法在进行转换创建对象
  2. 我们发现RouteDefinition,PredicateDefinition,FilterDefinition 都有一个带有String类型的构造函数,这细细猜想就可以得出,gateway的属性绑定,就是通过ObjectToObjectConverter的构造函数创建的。

本文地址:https://blog.csdn.net/he702170585/article/details/107332094

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网