SpringCloud版本Hoxton SR5 --- 第一讲:认识

什么是SpringCloud ?我用好理解的方式作比喻:

这里我们拿京东的网站做解释,京东不一定这么搞得,但是思想是一致的。首先SpringCloud一种微服务架构的实现;首先京东支持14亿人访问,这个架构一定不简单,而这个架构就是微服务架构。看例子:京东的首页网站:https://www.jd.com/ 京东的商品列表:https://list.jd.com/ 京东商品详情:https://item.jd.com/ ,购物车:https://cart.jd.com/ 等等。有没有发现一个问题,就是他们的网站地址不一样 ?这就证明了他们的业务是拆分开了,他们用到了微服务架构。

比如说,我们进京东,首先访问的是,京东的首页,首页也是访问人数最多的一个网站。这时候用一台、几台tomcat肯定是支撑不了这么大的并发访问量的。第二,选商品肯定要在很多商品列表中看一个自己喜欢的,这时候就是https://list.jd.com/对应的服务器返回的数据,还比如说京东的订单功能:https://order.jd.com/,我们一定是选好商品,准备付款的时候跳转到订单列表,这个功能用的人相对首页来说,并发访问量就没那么大了。

这时候为了不浪费资源,程序员可以怎么做呢 ?举个例子: 我把首页部署 1000台服务器,因为用的人最多,把订单部署200台服务器,因为用的人相对较少,我把订单的评论功能用50台服务器。想想如果没有架构的京东会是什么样子 ?就是把上面所有的功能都写在一个项目中,然后用很多很多的服务器部署这个一个项目,而且还不一定在618的时候,可以抗的住大量的访问。

所以什么是微服务呢 ?

就是把功能单独拆分开来,单独集群部署,这么一个思想,就是微服务架构思想。

把原本臃肿的一个项目的所有模块拆分开来并做到互相没有关联,甚至可以不使用同一个数据库,这就是微服务。

而SpringCloud就是为微服务提供技术支持的。SpringCloud不是微服务,只是为微服务提供解决方案。

这么说,还是很抽象,SpringCloud不是有很多很多技术吗 ?

 

下面就是用举例子的方式讲解:SpringCloud组件

 

再举例子 (讲解eureka  集群、心跳  与zookeeper类似):

传送门:SpringCloud版本Hoxton SR5 --- 第二讲:eureka 、eureka与zookeeper的区别与使用场景。

比如现在京东首页展示的代码写好了,我们把这个代码项目名管叫:jd-index ,然后把这个项目复制1000份部署到1000台服务器上,这时候就有一个问题,1000台服务器,1000个ip地址,我访问谁呢 ?这时候一定有人会说用nginx做反向代理。没错这是一个解决方案。

但是nginx还有个缺点,就是比如说 1000台,宕机500台,nginx在访问的时候,大多都是轮循机制,什么意思呢?比如说,1000个人访问nginx,但是宕机500台,这500台正好是配置的前500台宕机了,每台服务器自动访问两次再换服务器访问。就会造成所有人访问都是失败的,后1000-2000的访问是成功的。这就会造成很大一部分人,手机或者电脑提示404或者一直再访问中。 而eureka就可以解决这个问题,eureka自动识别到这500台服务器故障,然后自动将这500台服务器剔除去,那么这1000个人,就不可能访问到故障服务器。eureka把故障机踢出去后,就只剩下500台可以访问的机器,这样所有用户就都能访问成功。大大提高了用户的体验,当500个故障服务故障排除之后,又会自动重连。但值得注意的是,eureka解决的仅仅是将故障服务器剔除,他没有nginx的负载均衡功能,所以还要配合Ribbon的负载均衡策略,才可以完成一个真正的具有健壮性的负载均衡。

所以:eureka可以做到的仅仅是是微服务之间的心跳检测 和 微服务之间的相互注册。把故障微服务剔除,再把留下来的健康的服务的接口交给Ribbon做负载均衡。所以eureka 需要与 Ribbon + Fegin一起,才能实现负载均衡的完整功能。

 

接着上面的例子 (讲解Ribbon   与nginx类似)

传送门:SpringCloud版本Hoxton SR5 --- 第三讲:Ribbon 、Ribbon与Feign配合使用

上面说到了把500个故障服务器踢出eureka群聊。然后用nginx做负载均衡转发,还可以给某个服务器配置权重,或者简单的轮循、随机访问等。但这些功能虽然可以解决一部分并发访问的问题,但是访问规则较为固定。这时候就有了ribbon,ribbon在负载均衡的访问上提供了7中访问规则,并且ribbon也可以配置权重,不仅如此,还可以自定义服务器的访问规则,由程序员重写,以适应公司需求。

所以: Ribbon可以做到 配置服务器访问权重、7种已经写好的访问规则、重写服务器访问权重的规则(英文名:IRule 也就是负载均衡策略)、可以实现功能比较复杂的负载均衡功能。

 

还是接着上面的例子(讲解Feign)

还是上面的传送门,这里只是单独说一下:SpringCloud版本Hoxton SR5 --- 第三讲:Ribbon 、Ribbon与Feign配合使用

在日常工作中,一定用到过 webService、Apache cxf。他们的作用就是一样的。 比如写一段代码,调用一个 https://order.jd.com 类似的连接,然后再获取该链接返回的数据。 再比如说,当用到微服务架构的时候,京东用户登录后,可以看到购物车有多少件商品的提示, 这时候其实就是 用户模块的代码中,调用了购物车这个模块的查询功能。但是这两个模块,是两份不同的代码,也是部署到不同的服务器的,所以一定会在用户的模块中,调用一个http的链接,这个链接就是指向购物车模块的查询功能,并将查询到的结果返回给用户模块。

所以: Feign就是可以调用http链接,并且支持SpringMvc的注解,支持与Eureka和Ribbon组合使用以支持负载均衡。

 

继续 (讲解Hystrix 熔断、限流、降级)

传送门: SpringCloud版本Hoxton SR5 --- 第四讲:Hystrix 熔断、限流(线程)、降级

在大型的微服务项目中,有很多实际会发生的问题:比如:访问的人数太多了,淘宝节那一天晚上,每一台服务器压力都是特别大的。如果服务器压力太大,前面还有无穷无尽的访问进来,而服务器端的响应,比如查询数据库这时候就特别慢。这时候,就会发生雪崩效应。无数的访问进来,得不到及时处理,服务器CPU不堪重负,最终全部死机。淘宝节只能草草落幕,当天晚上就可以上世界新闻了。

Hystrix解决的就是,在访问的过程中,访问超过自定义的时间,访问异常(不管是系统Bug还是数据库超时,mq超时等)立即将该请求中断,防止服务调用端的线程被长时间占用,从而避免故障在分布式架构中蔓延,乃至雪崩。

比如:

访问到一个异常,或者超时了,或者熔断了。就调用一个一定会返回数据的方法。比如降级方法返回:商品没有了,或者系统升级,再或者等一会儿再试,这就叫降级

与此同时,一定时间范围内该服务被调用一定次数都失败了 并且调用失败率达到配置程度(默认50%),就触发熔断。 当一个微服务调用多次出现问题时(默认是10秒内20次调用失败,这个可以自己配置) 并且调用失败率达到配置程度(默认50%),hystrix就会采取熔断机制,不再继续调用有问题的接口(然后有问题的调用链会在默认5秒钟内,先试探性的先关闭熔断机制,但是如果这时候再(10秒内20次调用失败,失败率达到50%)又会重新进行熔断,直到该服务正常。这个现象就叫熔断

后面的尝试重连的机制就是 监控起作用。(运用中,其实就是对超时时间、熔断条件的配置)

限流就是限制某个微服务的使用量,这里涉及到线程。比如只允许10个线程同时访问该微服务,其他的请求,访问其他的微服务。并且这项技术,适用于Feign。 也就是远程调用,不单单适用于服务器内部,这就叫限流 。(应用场景:比如某台服务器的性能比较低)

所以: Hystrix就是解决当系统出现不正常情况的时候,让原本要完成的工作,停下来,节约系统资源,防止系统在等待中崩溃。

 

继续(zuul路由、过滤器、容错与回退)

传送门: SpringCloud版本Hoxton SR5 --- 第五讲:zuul 路由、过滤、容错与回退、集群、高可用

当没有Zuul的时候,我们调用微服务就是这种格式:

 http://微服务ID + 接口访问详细路径。        例如:http://SERVER-ORDER/order/query  

有了zuul以后,可以这样访问:  http:// zuul的ip:zuul的port/zuul配置地址 /order/query  (隐藏了微服务的名称)

Zuul会把自己与Eureka整合,并把自己注册成为Eureka服务下的应用,然后获取Eureka中注册上来的所有调用接口,最后,当准备调用服务、接口的时候,直接由zuul完成调用,脱离Eureka的控制。

路由:没有zuul的时候,当我们再调用微服务的时候,几乎都是通过微服务名或者直接ip+端口号来调用的,如果暴露微服务名可能导致黑客 集中火力进攻一部分服务器,导致服务瘫痪,这时候就是用zuul的路由功能做映射,暴露一个集群的统一访问路径,以减轻对服务器的威胁,这就是路由。

过滤:当一个ip或者国外某个地区的ip同时攻击服务器的时候,就可以用zuul的过滤功能,将这些地方的ip限制起来,让其请求还没有进入服务器的时候,被拦截掉,保证系统安全,还或者可以禁用某些客户等。主要就是可以在过滤器里写代码,跟java的过滤器差不多。比如:可以鉴权,过滤ip等等。

 * 过滤器(filter)是zuul的核心组件 zuul大部分功能都是通过过滤器来实现的。
 * <p>
 * zuul中定义了4种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期如下:
 * PRE:这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在 集群中选择请求的微服务、记录调试信息等。
 * ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服 务的请求,并使用 Apache HttpCIient或 Netfilx Ribbon请求微服务
 * POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准 的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
 * ERROR:在其他阶段发生错误时执行该过滤器。

容错与回退:zuul默认是整合了hystrix和ribbon的, 提供降级回退,那如何来使用hystrix呢? 我们自行写一个类,继承FallbackProvider 类,然后重写里面的方法。但是这个降级有点不一样的地方就是,因为zuul这个组件本身设计的位置就决定了,zuul 是在前端调用 与 微服务之间的组件。那么使用zuul的容错回退,相当于对整个系统设置统一的降级方法,所以使用起来要格外注意。

这里的降级,不是针对某一个接口降级,而是对整个微服务,比如:有order和item两个微服务,item微服务没有启动、或者宕机了。

这时候调用item所有接口都会走zuul的降级方法,但是同时order微服务启动是正常的,这时候order微服务的某些接口比如 /order/query 调用的接口有bug。这时候是不会走zuul的降级方法,而是走调用order的降级方法,如果没有配置降级方法,那么一定是404, 调用报错。

 

继续 (HystrixDashbord 监控)

传送门: SpringCloud版本Hoxton SR5 --- 第六讲:hystrixDashboard监控

上面的例子说了,当访问人数特别特别多的时候,微服务一定也是特别特别多的,一两个运维工程师肯定是不行的,至少也得3-4吧。(开玩笑自嘲一下,目前太多公司没有专门的运维工程师,全都是由程序员解决,导致程序员太多时间浪费在了修电脑上,并且不专业导致系统出问题也是很不应该的)事实上,HystrixDashbord就不该是程序员该管的事,他的作用就是监控,当一个请求进来了,直到请求结束,他监控的是:请求经过了哪些微服务、调用了哪些接口、在哪个微服务出了问题,

所以:HystrixDashbord监控:出问题的频率、成功数、熔断数、请求出错的数量、超时数、延迟统计等等。

 

spring-cloud config  (动态配置)

传送门:SpringCloud版本Hoxton SR5 --- 第七讲:SpringCloud Config 分布式配置中心+整合bus、rabbitmq、actuator

springcloud config解决的就是:比如我们有50个微服务,他们的数据库密码被修改了。现在要修改这50个微服务的数据库密码。

再比如,我们可以在代码里用@Value("xxx")获取配置数据吧,现在配置的xxx的数据值为false,某一天我们要需求变了,这些false要全部修改为true。

通常情况下,是不是打开代码 ?一个一个的修改 ?然后再一个一个的部署 ?至少这个过程是特别麻烦的吧。

而springcloud-config解决的就是这一类的问题。springcloud config 可以在外部修改配置文件(例如:git仓库),代码完全不用修改,然后重新启动一下被修改的微服务就好了。另外springcloud-config有客户端,也有服务端。服务端可以是单独的一个微服务。

他的原理就是:

我们按照一定规则将配置信息写好,保存到本地 或者 git云端。然后部署springcloud-config的服务端,就可以获取 本地 或者 git云端的配置文件。然后所有使用了springcloud-config客户端的微服务,重启一下,就会通过springcloud config服务端拿到git仓库这些配置然后启动微服务。在git仓库中的配置,还可以分环境部署(dev/test/pro/uat等)非常的方便,使用起来更加轻松,不需要程序员自己打开代码一个一个修改,运维工程师,可以直接修改git仓库里的配置,然后重启服务器就好了。 这就是spring-cloud-config 可以完成的一些主要功能。

有没有感觉上面的springcloud config并没有想象中的那么好 ? 我还需要重启服务器 ?那我还不如就在代码里改了,然后上传到git仓库,然后用Jenkins自己去git仓库获取代码,完成自动部署啊。

当然如果在代码里修改配置,还需要编译,打包,这也是不理智的。但是重启服务器,有点不开心。修改数据库配置,我重启服务器,我能接受,但是修改一个简单的controller里需要的属性,还要重启,就不是很开心。

这时候又有了另一个技术。springcloud的消息总线 : SpringCloud Bus 这个消息总线呢,又需要整合消息组件 (kafka/rabbitmq,springcloud他有专门整合kafka和rabbitmq的包)还有spring的 spring-boot-starter-actuator 组件(其实springcloud config动态修改配置的功能,就是actuator组件触发的,并且用的是post调用一个http地址,调用成功之后没有返回值)。写到这里我真的想吐槽springcloud了。太特么麻烦了。你直接集成好了不好吗 ?还要劳资去集成,组件多的一箩筐,学习成本也太大了吧。他的这个原理呢:上面不是说了么,springcloud config的服务端是用来读取git仓库中配置的。springcloud config客户端是用来读取 springcloud config服务端在git中获取到的配置信息。那这个消息总线bus呢,需要添加到所有使用了springcloud config客户端的微服务中去,还要配置mq的ip、端口、用户名密码。配置好了之后,所有微服务还要配置 spring-boot-starter-actuator,他的这个作用就好比监控,当调用某一个使用了springcloud config+bus+actuator的微服务的 http://ip:端口/actuator/bus-refresh 这个地址的时候 ,就通过消息总线给mq发送一条信息,然后呢,其他所有使用bus消息总线的的微服务,都会通过mq收到一条命令,这个命令就是告诉所有使用了springcloud config的客户端,需要修改配置了,你去获取配置。这还没完,上面只是说,各个微服务已经拿到了修改的配置,还需要指定某个类,是否使用这个更改了的配置,这时候还需要在修改的类上加@RefreshScope注解,表示如果配置修改了,这个类,及时使用修改过的配置。

使用起来就简单多了:当在git仓库修改好配置后,直接使用post请求调用一个 http://localhost:8080/actuator/bus-refresh  这个地址,springcloud config的动态配置就完成了。上面那个http://localhost:8080/actuator/bus-refresh的localhost:8080,必须是任意一个使用了springcloud config + bus +actuator的微服务的 ip和端口。这样springcloud config的动态配置的功能才算真正的完成。

 

最后一个了 (分布式链路跟踪 Sleuth 整合Zipkin +Elasticsearch 做数据持久化  用于查看日志)

传送门:SpringCloud版本Hoxton SR5 --- 第八讲:Sleuth 分布式链路跟踪 整合Zipkin + Elasticsearch持久化

解决的问题:

  • 如何串联调用链,快速定位问题
  • 如何理清楚,微服务之间的依赖关系
  • 如何进行各个服务接口的性能分折
  • 如何跟踪业务流的处理

在调用关系复杂的微服务中,如果某个微服务的接口出了问题,要快速的定位到该请求经过哪些微服务,调用了哪些接口,就需要Sleuth 分布式链路跟踪:

比如说当调用开始的时候,会为这个请求生成一个Trace ID(类似UUID的序号),调用过程中,会把这个Trace ID一直传递下去,用于标记该请求,后面可以根据Trace ID找到该请求经过了哪些微服务。

再说该调用链中,比如:A微服务调用B微服的过程,有多个Span ID的标识,比如代码运行A微服务的时候有个Span ID,A微服务调用B微服务的网络请求过程中也会有一个Span ID,B微服务代码执行的过程也会有一个Span ID,最后可以通过这些ID计算出执行时间。用于调优。

Spring Cloud Sleuth可以追踪10种类型的组件:async、Hystrix,messaging,websocket,rxjava,scheduling,web(Spring MVC Controller,Servlet),webclient(Spring RestTemplate)、Feign、Zuul

所以 Sleuth的作用就是记录:请求过程中,调用的每个微服务,请求路径,经过了哪些服务组件等等信息给生成出来。

然后使用Zipkin的客户端将这些信息,发送给Zipkin的服务端,然后Zipkin服务端整合这些数据,并提供UI界面用于查看Sleuth记录的信息。

这里又有一个问题,Zipkin服务端,是将这些信息保存在内存中的,当数据量太大的时候服务器的内存不够用,并且当停掉Zipkin服务端的时候,这些信息就会在内存中被清除。这时候,就使用Elasticsearch保存数据 (这里可以理解为数据库) ,他就将Zipkin整合好的信息,保存在硬盘中(持久化)。

 

到这里,SpringCloud的组件我就写的差不多了,谢谢观看。

 

嘿嘿。

 

 

已标记关键词 清除标记
pom.xml 配置 ``` <dependencies> <!--微服务注册--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--网关配置--> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-zuul --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <!--限流--> <!-- https://mvnrepository.com/artifact/com.marcosbarbero.cloud/spring-cloud-zuul-ratelimit --> <dependency> <groupId>com.marcosbarbero.cloud</groupId> <artifactId>spring-cloud-zuul-ratelimit</artifactId> <version>2.3.0.RELEASE</version> </dependency> <!--限流redis数据库记录数据--> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--OAuth--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--自定义config配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> <!-- 被zipkin服务追踪的启动依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> <!--配置rabbitmq--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rabbit</artifactId> </dependency> </dependencies> ``` application.yml ``` server: port: 6020 spring: application: name: Gateway-Zuul #对曝光的微服务的名称 #配置redis redis: host: 127.0.0.1 port: 6379 password: admin jedis: pool: max-active: 100 max-idle: 8 min-idle: 4 max-wait: 10000 timeout: 3000 #rabbitmq rabbitmq: host: 127.0.0.1 port: 5672 username: admin password: admin #zipkin在rabbitmq消息队列zipkin zipkin: sender: type: rabbit rabbitmq: queue: zipkin #被追踪的可能性,默认是0.1 表示百分之10 sleuth: sampler: probability: 1.0 eureka: client: service-url: defaultZone: http://Eureka7001.com:7001/eureka/ registry-fetch-interval-seconds: 5 # 默认为30秒 表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒 instance: instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}} #修改之后的ip prefer-ip-address: true #访问路径显示IP地址 zuul: host: connect-timeout-millis: 15000 #HTTP连接超时要比Hystrix的大 socket-timeout-millis: 60000 #socket超时 ignored-services: "*" # 不允许用微服务名访问了,如果禁用所有的,可以使用 "*" routes: OAuth-server: /auth/** sensitive-headers: #允许传递敏感信息 #限流配置 ratelimit: enabled: true repository: REDIS behind-proxy: true add-response-headers: false default-policy-list: #optional - will apply unless specific policy exists - limit: 20 #optional - request number limit per refresh interval window quota: 1 #optional - request time limit per refresh interval window (in seconds) refresh-interval: 1 #default value (in seconds) type: #optional # - user - origin - url - httpmethod security: oauth2: client: #令牌端点 access-token-uri: http://localhost:${server.port}/auth/oauth/token #授权端点 user-authorization-uri: http://localhost:${server.port}/auth/oauth/authorize #OAuth2客户端ID client-id: test #OAuth2客户端密钥 client-secret: test authorization: check-token-access: http://localhost:${server.port}/auth/oauth/check_token resource: jwt: key-value: jkdfjkdf ribbon: ReadTimeout: 10000 ConnectTimeout: 10000 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 3000 circuitBreaker: enabled: true requestVolumeThreshold: 10 sleepWindowInMilliseconds: 10000 errorThresholdPercentage: 60 ``` 报错信息: ``` 2020-02-09 17:04:44.448 ERROR [Gateway-Zuul,bb484313c41a709a,0245f4527d3b0826,true] 20368 --- [ask-scheduler-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessagingException: Failed to invoke method; nested exception is java.lang.UnsupportedOperationException: This converter does not support this method at org.springframework.integration.endpoint.MethodInvokingMessageSource.doReceive(MethodInvokingMessageSource.java:115) at org.springframework.integration.endpoint.AbstractMessageSource.receive(AbstractMessageSource.java:167) at org.springframework.integration.endpoint.SourcePollingChannelAdapter.receiveMessage(SourcePollingChannelAdapter.java:250) at org.springframework.integration.endpoint.AbstractPollingEndpoint.doPoll(AbstractPollingEndpoint.java:359) at org.springframework.integration.endpoint.AbstractPollingEndpoint.pollForMessage(AbstractPollingEndpoint.java:328) at org.springframework.integration.endpoint.AbstractPollingEndpoint.lambda$null$1(AbstractPollingEndpoint.java:275) at org.springframework.integration.util.ErrorHandlingTaskExecutor.lambda$execute$0(ErrorHandlingTaskExecutor.java:57) at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:55) at org.springframework.integration.endpoint.AbstractPollingEndpoint.lambda$createPoller$2(AbstractPollingEndpoint.java:272) at org.springframework.cloud.sleuth.instrument.async.TraceRunnable.run(TraceRunnable.java:67) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.UnsupportedOperationException: This converter does not support this method at org.springframework.integration.support.converter.DefaultDatatypeChannelMessageConverter.toMessage(DefaultDatatypeChannelMessageConverter.java:85) at org.springframework.messaging.converter.CompositeMessageConverter.toMessage(CompositeMessageConverter.java:83) at org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry$FunctionInvocationWrapper.lambda$convertOutputValueIfNecessary$2(BeanFactoryAwareFunctionRegistry.java:620) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1359) at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126) at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464) at org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry$FunctionInvocationWrapper.convertOutputValueIfNecessary(BeanFactoryAwareFunctionRegistry.java:626) at org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry$FunctionInvocationWrapper.doApply(BeanFactoryAwareFunctionRegistry.java:569) at org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry$FunctionInvocationWrapper.get(BeanFactoryAwareFunctionRegistry.java:474) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282) at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:266) at org.springframework.integration.endpoint.MethodInvokingMessageSource.doReceive(MethodInvokingMessageSource.java:112) ... 19 moreyi ```
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页