当前位置:首页 > 科技  > 软件

8000字+22张图探秘SpringCloud配置中心的核心原理

来源: 责编: 时间:2023-10-17 09:38:54 856观看
导读大家好,我是三友~~这篇文章来扒一扒SpringCloud配置中心的核心原理。不知你是否跟我一样,在刚开始使用SpringCloud配置中心的时候也有很多的疑惑:SpringCloud是什么时候去拉取配置中心的?配置中心客户端的配置信息为什么

大家好,我是三友~~OOE28资讯网——每日最新资讯28at.com

这篇文章来扒一扒SpringCloud配置中心的核心原理。OOE28资讯网——每日最新资讯28at.com

不知你是否跟我一样,在刚开始使用SpringCloud配置中心的时候也有很多的疑惑:OOE28资讯网——每日最新资讯28at.com

  • SpringCloud是什么时候去拉取配置中心的?
  • 配置中心客户端的配置信息为什么要写在bootstrap文件中?
  • 对象中注入的属性是如何动态刷新的?
  • 一些开源的配置中心是如何整合SpringCloud的?
  • ...

本文就通过探讨上述问题来探秘SpringCloud配置中心核心的底层原理。OOE28资讯网——每日最新资讯28at.com

从SpringBoot的启动过程说起

在SpringBoot启动的时候会经历一系列步骤,核心就是SpringApplication的run方法的逻辑OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

整个过程大致可以划分为三个阶段:OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

ApplicationContext刷新前阶段,这个阶段主要也干三件事OOE28资讯网——每日最新资讯28at.com

  • 准备Environment(注意我这里加粗了,你懂得),也就是准备SpringBoot的整个外部化配置的对象
  • 创建一个ApplicationContext
  • 为ApplicationContext做一些准备工作

图片图片OOE28资讯网——每日最新资讯28at.com

ApplicationContext刷新阶段,这个阶段其实就是调用ApplicationContext#refresh方法来刷新容器OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

刷新的整个过程可以看我之前写的万字+20张图剖析Spring启动时12个核心步骤这篇文章OOE28资讯网——每日最新资讯28at.com

ApplicationContext刷新后阶段,这个阶段其实就是收尾的阶段,这个过程其实没有什么非常核心的事OOE28资讯网——每日最新资讯28at.com

ok,在说完上面这三个阶段之后,思考一个问题OOE28资讯网——每日最新资讯28at.com

你觉得在上面的三个阶段,哪个阶段最有可能从配置中心拉取配置?OOE28资讯网——每日最新资讯28at.com

其实稍微思考一下,肯定是想到的就是刷新前阶段OOE28资讯网——每日最新资讯28at.com

因为我已经明示了,准备EnvironmentOOE28资讯网——每日最新资讯28at.com

玩笑归玩笑,为什么是这个阶段?OOE28资讯网——每日最新资讯28at.com

很好理解,因为这个阶段是准备Environment,也就是准备外部化配置OOE28资讯网——每日最新资讯28at.com

只需要在这个阶段加载配置中心的配置,放到Environment中,后面在整个ApplicationContext刷新阶段创建Bean的时候,就可以使用到配置中心的配置了OOE28资讯网——每日最新资讯28at.com

其实不光是配置中心的配置,比如配置文件的配置,也是在这里阶段读取的OOE28资讯网——每日最新资讯28at.com

至于如何实现的,我们接着往下瞅OOE28资讯网——每日最新资讯28at.com

准备Environment的核心操作

上一节得出一个结论OOE28资讯网——每日最新资讯28at.com

准备Environment,也就是prepareEnvironment方法的实现,是拉取配置的核心OOE28资讯网——每日最新资讯28at.com

prepareEnvironment方法prepareEnvironment方法OOE28资讯网——每日最新资讯28at.com

不过在说这个方法之前,先来讲一下一些前置操作OOE28资讯网——每日最新资讯28at.com

前置操作

在SpringApplication创建的时候,会去加载spring.factories中的一些对象,其中就包括:OOE28资讯网——每日最新资讯28at.com

  • org.springframework.context.ApplicationListener键对应的ApplicationListener的实现

图片OOE28资讯网——每日最新资讯28at.com

  • org.springframework.boot.SpringApplicationRunListener键对应的SpringApplicationRunListener的实现类

图片OOE28资讯网——每日最新资讯28at.com

SpringApplicationRunListener仅仅只有一个实现EventPublishingRunListenerOOE28资讯网——每日最新资讯28at.com

EventPublishingRunListener

构造的时候会创建一个SimpleApplicationEventMulticaster,再将加载的ApplicationListener添加进去OOE28资讯网——每日最新资讯28at.com

SimpleApplicationEventMulticaster是用来发布事件用的,不清楚的话可以看三万字盘点Spring 9大核心基础功能这篇文章OOE28资讯网——每日最新资讯28at.com

按照传统,画张图来理一下这部分前置操作OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

prepareEnvironment的核心逻辑

接着来讲一下prepareEnvironment方法OOE28资讯网——每日最新资讯28at.com

prepareEnvironment方法prepareEnvironment方法OOE28资讯网——每日最新资讯28at.com

这个方法会首先创建一个Environment对象OOE28资讯网——每日最新资讯28at.com

之后会执行这么一行方法,传入刚刚创建的Environment对象OOE28资讯网——每日最新资讯28at.com

listeners.environmentPrepared(environment);

这个方法最终会走到这个方法

EventPublishingRunListener#environmentPrepared

图片图片OOE28资讯网——每日最新资讯28at.com

这个方法最终会发布一个ApplicationEnvironmentPreparedEvent事件OOE28资讯网——每日最新资讯28at.com

而对这个事件有两个特别重要的监听器:OOE28资讯网——每日最新资讯28at.com

  • ConfigFileApplicationListener
  • BootstrapApplicationListener

这些监听器都是通过前置操作从spring.factories配置文件中加载的OOE28资讯网——每日最新资讯28at.com

ConfigFileApplicationListener,用来处理配置文件的,他会解析配置文件的配置,放到Environment中OOE28资讯网——每日最新资讯28at.com

BootstrapApplicationListener这个跟本文探讨的主题相关了,它是用来专门来跟配置中心交互的OOE28资讯网——每日最新资讯28at.com

到这,我们就找到了SpringCloud配置中心配置拉取的整个入口逻辑OOE28资讯网——每日最新资讯28at.com

不过在分析BootstrapApplicationListener是如何从配置中心拉取配置的之前,先来张图总结一下这部分prepareEnvironment的操作OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

SpringCloud是如何巧妙地拉取配置的?

在BootstrapApplicationListener中,他首先也会创建一个SpringApplication去执行OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

其实本质上就是创建一个Spring容器,也就是ApplicationContextOOE28资讯网——每日最新资讯28at.com

这个容器非常重要,这个容器是专门用来跟配置中心交互的OOE28资讯网——每日最新资讯28at.com

这个容器在创建的时候会给它两个比较重要的配置OOE28资讯网——每日最新资讯28at.com

第一个就是设置这个容器所用的配置文件的名称OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

默认就是bootstrapOOE28资讯网——每日最新资讯28at.com

这就解释了为什么配置中心的配置信息需要写在bootstrap配置文件中OOE28资讯网——每日最新资讯28at.com

第二个就是会加入一个配置类OOE28资讯网——每日最新资讯28at.com

BootstrapImportSelectorConfiguration

图片图片OOE28资讯网——每日最新资讯28at.com

这个配置类又会通过@Import注解导入另一个配置类OOE28资讯网——每日最新资讯28at.com

BootstrapImportSelector

图片图片OOE28资讯网——每日最新资讯28at.com

BootstrapImportSelector实现了(间接)ImportSelector接口OOE28资讯网——每日最新资讯28at.com

那么这个容器在启动的时候,就会调用BootstrapImportSelector的selectImports方法的实现获取到一些配置类OOE28资讯网——每日最新资讯28at.com

而BootstrapImportSelector的selectImports实现从截图中也就可以看出OOE28资讯网——每日最新资讯28at.com

他会加载所有的spring.factories中的键为org.springframework.cloud.bootstrap.BootstrapConfiguration的配置类OOE28资讯网——每日最新资讯28at.com

其实这里@BootstrapConfiguration的作用其实跟@EnableAutoConfiguration的作用是差不多的,都是用来导入配置类的OOE28资讯网——每日最新资讯28at.com

所以,总的来说,这个用来跟配置中心交互的Spring容器最最主要就是干两件事:OOE28资讯网——每日最新资讯28at.com

  • 加载bootstrap配置文件
  • 加载所有的spring.factories中的键为org.springframework.cloud.bootstrap.BootstrapConfiguration对应的配置类

图片图片OOE28资讯网——每日最新资讯28at.com

而在spring-cloud-context包下,@BootstrapConfiguration会导入一个很重要的配置类OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

PropertySourceBootstrapConfiguration

图片图片OOE28资讯网——每日最新资讯28at.com

PropertySourceBootstrapConfiguration

这个配置类中会注入这么一个集合对象OOE28资讯网——每日最新资讯28at.com

PropertySourceLocator

PropertySourceLocatorPropertySourceLocatorOOE28资讯网——每日最新资讯28at.com

这个接口非常非常重要,先来看看注释OOE28资讯网——每日最新资讯28at.com

Strategy for locating (possibly remote) property sources for the Environment. Implementations should not fail unless they intend to prevent the application from starting.OOE28资讯网——每日最新资讯28at.com

我用我的四级英语功力给大家翻译一下OOE28资讯网——每日最新资讯28at.com

以一种策略的方式为Environment定位(可能是远程)属性配置(PropertySource)。实现不应该失败,除非打算阻止应用程序启动。OOE28资讯网——每日最新资讯28at.com

从这个翻译后的意思就是说,这个接口是用来定位,也就是说获取属性配置的OOE28资讯网——每日最新资讯28at.com

并且可能是远程告诉我们一个很重要的信息,那就是获取的配置信息不仅仅可以存在本地,而且还可以存在远程。OOE28资讯网——每日最新资讯28at.com

远程?作者这里就差直接告诉你可以从配置中心获取了。。OOE28资讯网——每日最新资讯28at.com

所以这个接口的作用就是用配置中心获取配置的!OOE28资讯网——每日最新资讯28at.com

那么自然而然不同的配置中心要想整合到SpringCloud就得实现这个接口OOE28资讯网——每日最新资讯28at.com

当注入完PropertySourceLocator集合之后,在某个阶段会调用所有的PropertySourceLocator,获取配置中心中的配置图片OOE28资讯网——每日最新资讯28at.com

之后在把这些配置放到Environment中OOE28资讯网——每日最新资讯28at.com

这样在ApplicationContext的刷新阶段就可以使用到配置中心的那些配置了OOE28资讯网——每日最新资讯28at.com

小总结

到这我们就弄明白了在项目启动中加载配置中心的配置了OOE28资讯网——每日最新资讯28at.com

其实就是项目在启动时会额外创建一个跟配置中心相关的Spring容器OOE28资讯网——每日最新资讯28at.com

这个容器会去加载bootstrap配置文件和所有的spring.factories中的键为org.springframework.cloud.bootstrap.BootstrapConfiguration对应的配置类OOE28资讯网——每日最新资讯28at.com

之后会去调用这个容器中所有的PropertySourceLocator对象,从配置中心获取配置OOE28资讯网——每日最新资讯28at.com

再放到Environment中就完成了启动时从配置中心获取配置的方式OOE28资讯网——每日最新资讯28at.com

最后,来张全家福概括一下前面整体的步骤OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

如何动态刷新Bean的属性?

我们都知道,要想实现配置属性的动态刷新,需要在类上加上一个注解OOE28资讯网——每日最新资讯28at.com

@RefreshScopeOOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

重点来了OOE28资讯网——每日最新资讯28at.com

加了@RefreshScope注解的Bean,就拿上图中的UserService举例OOE28资讯网——每日最新资讯28at.com

Spring在生成的时候会生成两个UserService的Bean:OOE28资讯网——每日最新资讯28at.com

  • 第一个是UserService的代理动态代理的Bean,后面我称为第一个Bean
  • 第二个就是UserService这个Bean,后面我称为第二个Bean

当你在其它类中需要注入一个UserService时,真正注入的是第一个Bean,也就是动态代理的BeanOOE28资讯网——每日最新资讯28at.com

当你使用这个注入的动态代理的Bean的时候,他会去找第二个Bean,也就是真正的UserService这个Bean,然后调用对应的方法OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

比如你调用注入的UserService代理对象的getUsername方法,最终就会调用到第二个BeangetUsername方法OOE28资讯网——每日最新资讯28at.com

获取到的username属性值自然也就是第二个Bean中的username值OOE28资讯网——每日最新资讯28at.com

那么为什么要生成两个Bean?OOE28资讯网——每日最新资讯28at.com

接着往下瞅OOE28资讯网——每日最新资讯28at.com

在SpringCloud中有这么一项规定OOE28资讯网——每日最新资讯28at.com

当配置中心客户端一旦感知到服务端的某个配置有变化的时候,需要发布一个RefreshEvent事件来告诉SpringCloud配置有变动OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

在SpringCloud中RefreshEventListener类会去监听这个事件OOE28资讯网——每日最新资讯28at.com

RefreshEventListenerRefreshEventListenerOOE28资讯网——每日最新资讯28at.com

一旦监听到这个事件,SpringCloud会再次从配置中心拉取配置OOE28资讯网——每日最新资讯28at.com

这个拉取配置的核心逻辑跟启动时拉取配置的核心逻辑是一样的OOE28资讯网——每日最新资讯28at.com

也是通过 BootstrapApplicationListener 来实现的OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

这部分代码逻辑在ContextRefresher类中,顺着RefreshEventListener就能看到,有兴趣可以扒一扒OOE28资讯网——每日最新资讯28at.com

怕你忘了,我再把上面拉取配置的图拿过来OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

有了最新的配置之后,就会进行一步骚操作来移花接木”刷新“注入到对象的属性OOE28资讯网——每日最新资讯28at.com

这个骚操作就是销毁所有的前面提到的第二个Bean,但是第一个Bean,也就是代理对象保持不变OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

当程序运行调用代理对象的方法的时候,发现第二个Bean没有了,此时他就会去重新创建第二个Bean,也就是重新创建一个UserService对象OOE28资讯网——每日最新资讯28at.com

由于此时已经拉到最新的配置了,也就是这个被重新创建的UserService对象注入的就是最新的属性了OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

之后再调用的这个新创建的第二个Bean,拿到的自然就是最新的配置OOE28资讯网——每日最新资讯28at.com

所以,给你的感觉是对象的属性发生了变化,实际上是真正被调用的对象重新创建了OOE28资讯网——每日最新资讯28at.com

所以这招移花接木还是有点意思的!OOE28资讯网——每日最新资讯28at.com

小总结

其实到这就弄明白了Bean的属性动态刷新的原理OOE28资讯网——每日最新资讯28at.com

其实就是当配置中心客户端发现服务端的配置有变化,需要发送一个RefreshEvent事件来告诉SpringCloud配置有变动OOE28资讯网——每日最新资讯28at.com

SpringCloud会去监听这个事件,按照项目启动的方式重新拉取配置中心最新的属性配置OOE28资讯网——每日最新资讯28at.com

当拉取完属性配置之后,就会销毁所有的第二个Bean,也就是真正被使用的BeanOOE28资讯网——每日最新资讯28at.com

之后当第一个Bean(动态代理的Bean)需要使用这个第二个Bean时,就会重新创建这个第二个BeanOOE28资讯网——每日最新资讯28at.com

此时由于已经有最新的配置了,那么创建的这个第二个Bean就会被注入最新的属性,这样就实现了属性的”刷新“OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

补充个东西:@RefreshScope的秘密

上面大致说了@RefreshScope动态刷新的原理OOE28资讯网——每日最新资讯28at.com

这里我补充一下@RefreshScope代码层面的实现原理OOE28资讯网——每日最新资讯28at.com

本来这部分原理我是写在前面的,但是我发现这块比较绕,怕打断文章的节奏,所以就准备删除了OOE28资讯网——每日最新资讯28at.com

但是想想既然都写了,那么就给放到补充里面吧,看不懂也不耽误前面的理解OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

这个注解是个衍生注解,真正起作用的就是@Scope注解OOE28资讯网——每日最新资讯28at.com

@Scope注解并不陌生,他其实是定义Bean的作用域OOE28资讯网——每日最新资讯28at.com

比如多例(原型),就可以加上@Scope("prototype")注解OOE28资讯网——每日最新资讯28at.com

还有一些八股文常背的作用域,比如session作用域等等OOE28资讯网——每日最新资讯28at.com

而@RefreshScope也可以看做是一种Bean的作用域,名字叫做refreshOOE28资讯网——每日最新资讯28at.com

这些除了单例和多例之外的作用域的底层实现逻辑都是一样的OOE28资讯网——每日最新资讯28at.com

这些带有作用域的Bean相比于普通的单例Bean主要有以下几点不同:OOE28资讯网——每日最新资讯28at.com

  • 会注册两个Bean,这个前面已经提到过
  • 保存的地方不同,比如单例Bean最终会存在三级缓存中的第一级缓存中,而不同作用域的Bean是存在不同的地方的

先说会注册两个Bean,还是以前面提到的UserService举个例子,这两个Bean分别是OOE28资讯网——每日最新资讯28at.com

  • 第一个Bean的Bean名称为userService,Bean class为ScopedProxyFactoryBean.class,这个scope为默认,也就是单例
  • 第二个Bean的Bean名称为scopedTarget.userService,Bean class为UserService.class,scope为refresh(如果是session作用域就是session)

第一个Bean的class为ScopedProxyFactoryBean,是个FactoryBean的实现OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

这个最终会生成一个代理对象,上面的例子就是为UserService生成一个代理对象,并且由于是单例的,所以最终这个对象会被放到一级缓存中,我们使用时注入的也就是这个对象OOE28资讯网——每日最新资讯28at.com

第二个Bean的class是UserService,所以生成的就是真正的UserService对象,但是由于scope为refresh,所以不会存在第一级缓存中OOE28资讯网——每日最新资讯28at.com

这部分注册两个Bean的代码是在ScopedProxyUtils#createScopedProxy方法中,有兴趣的可以扒扒OOE28资讯网——每日最新资讯28at.com

再来讲一讲保存的地方不同OOE28资讯网——每日最新资讯28at.com

不同的作用域都需要实现一个Scope接口来存放对应的BeanOOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

比如refresh、session作用域都有对应的实现OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

也就是通过Scope就可以管理不同作用域的BeanOOE28资讯网——每日最新资讯28at.com

所以,对于refresh这个作用域来说,他的所有的Bean都在RefreshScope中OOE28资讯网——每日最新资讯28at.com

后面说的销毁,只需要移除RefreshScope中的Bean就可以了OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

代码也在ContextRefresher类中

开源配置中心是如何整合SpringCloud的?

首先我们再来梳理一下拉取配置和刷新配置的核心关键点OOE28资讯网——每日最新资讯28at.com

拉取配置关键点就是项目启动的时候(也包括重新拉取配置),会去创建一个容器OOE28资讯网——每日最新资讯28at.com

这个容器只读取bootstrap配置文件和spring.factories中的键为org.springframework.cloud.bootstrap.BootstrapConfiguration对应的配置类OOE28资讯网——每日最新资讯28at.com

之后会获取这个容器中的PropertySourceLocator,从而获取配置中心的配置OOE28资讯网——每日最新资讯28at.com

刷新配置关键点就是一旦配置中心配置变动,就需要发送RefreshEvent事件,之后一系列刷新操作都是由SpringCloud的来完成的OOE28资讯网——每日最新资讯28at.com

所以,配置中心整合到SpringCloud其实就很简单,就两点OOE28资讯网——每日最新资讯28at.com

第一点就是需要实现PropertySourceLocator,并且配置中心一些相关的Bean需要通过org.springframework.cloud.bootstrap.BootstrapConfiguration来装配到这个容器中OOE28资讯网——每日最新资讯28at.com

第二点,当配置发生变更需要发送RefreshEvent事件,这部分配置中心一些相关的Bean配置肯定是需要通过自动装配来完成OOE28资讯网——每日最新资讯28at.com

有了这两点我们来看看Nacos作为配置中心是如何整合到SpringCloud的OOE28资讯网——每日最新资讯28at.com

我们直接看Nacos的spring.factories文件OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

NacosConfigBootstrapConfiguration是用来实现第一点的OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

除了Nacos自己的一些Bean,他还声明了一个NacosPropertySourceLocator这个BeanOOE28资讯网——每日最新资讯28at.com

NacosPropertySourceLocatorNacosPropertySourceLocatorOOE28资讯网——每日最新资讯28at.com

这个Bean就实现了PropertySourceLocator接口OOE28资讯网——每日最新资讯28at.com

第二点的实现就是通过NacosConfigAutoConfiguration配置类来实现的OOE28资讯网——每日最新资讯28at.com

这里面有这么一个BeanOOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

这个Bean就实现了配置变化发送事件的操作OOE28资讯网——每日最新资讯28at.com

图片图片OOE28资讯网——每日最新资讯28at.com

除了Nacos,比如说Consul作为配置中心的时候也是这么一套实现逻辑OOE28资讯网——每日最新资讯28at.com

但是值的注意的是,像Apollo配置中心,他并没有适配SpringCloud这套规范OOE28资讯网——每日最新资讯28at.com

当然,如果你有兴趣,可以自己实现Apollo适配SpringCloud这套规范OOE28资讯网——每日最新资讯28at.com


OOE28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-13640-0.html8000字+22张图探秘SpringCloud配置中心的核心原理

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 掌握这五种多线程方法,提高Java代码效率

下一篇: 从0手写一个多线程日志包

标签:
  • 热门焦点
  • 小米降噪蓝牙耳机Necklace分享:听一首歌 读懂一个故事

    在今天下午的小米Civi 2新品发布会上,小米还带来了一款新的降噪蓝牙耳机Necklace,我们也在发布结束的第一时间给大家带来这款耳机的简单分享。现在大家能见到最多的蓝牙耳机
  • vivo TWS Air开箱体验:真轻 臻好听

    在vivo S15系列新机的发布会上,vivo的最新款真无线蓝牙耳机vivo TWS Air也一同发布,本次就这款耳机新品给大家带来一个简单的分享。外包装盒上,vivo TWS Air保持了vivo自家产
  • Flowable工作流引擎的科普与实践

    一.引言当我们在日常工作和业务中需要进行各种审批流程时,可能会面临一系列技术和业务上的挑战。手动处理这些审批流程可能会导致开发成本的增加以及业务复杂度的上升。在这
  • 慕岩炮轰抖音,百合网今何在?

    来源:价值研究所 作者:Hernanderz“难道就因为自己的一个产品牛逼了,从客服到总裁,都不愿意正视自己产品和运营上的问题,选择逃避了吗?”这一番话,出自百合网联合创
  • 冯提莫签约抖音公会 前“斗鱼一姐”消失在直播间

    来源:直播观察提起“冯提莫”这个名字,很多网友或许听过,但应该不记得她是哪位主播了。其实,作为曾经的“斗鱼一姐”,冯提莫在游戏直播的年代影响力不输于现
  • 微博大门常打开,迎接海外画师漂洋东渡

    作者:互联网那些事“起猛了,我能看得懂日语了”。“为什么日本人说话我能听懂?”“中文不像中文,日语不像日语,但是我竟然看懂了”…&hell
  • OPPO K11采用全方位护眼屏:三大护眼能力减轻视觉疲劳

    日前OPPO官方宣布,全新的OPPO K11将于7月25日正式发布,将主打旗舰影像,和同档位竞品相比,其最大的卖点就是将配备索尼IMX890主摄,堪称是2000档位影像表
  • 苹果140W USB-C充电器:采用氮化镓技术

    据10 月 30 日 9to5 Mac 消息报道,当苹果推出新的 MacBook Pro 2021 时,该公司还推出了新的 140W USB-C 充电器,附赠在 MacBook Pro 16 英寸机型的盒子里,也支
  • “买真退假” 这种“羊毛”不能薅

    □ 法治日报 记者 王春   □ 本报通讯员 胡佳丽  2020年初,还在上大学的小东加入了一个大学生兼职QQ群。群主“七王”在群里介绍一些刷单赚
Top