• [Java] Spring boot 的核心文件
    Spring boot 有两种类型的配置文件:application 和 bootstrap;application配置是应用级别的,是当前应用的配置文件;bootstrap配置文件是系统级别的,用来加载外部配置,也可以定义系统不会变化的属性;bootstrap文件的加载先于application。
  • [Java] Spring boot
    Spring boot 是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
  • [Java] spring mvc 和struts
    spring mvc 和 struts 的区别是什么?
  • [问题求助] spring cloud 项目用 CSE 框架改造,配置中心这些配置如何迁移?
    spring cloud 项目 迁移到 CSE 框架。配置中心的那些yaml 文件,如果迁移到 CSE 配置中心呢? CSE 全局配置项,跟spring cloud 配置中心的 数据如何迁移 让 项目通用的配置抽取出来!
  • [技术干货] 【深圳HDZ】王松-Spring Boot要么学?要不要先学 SSM?
          可能很多刚接触 Spring Boot 的小伙伴都会有这样的疑问,Spring Boot 要怎么学,要不要先学 SSM?今天结合自己的经验,和大家说一说我的看法,也顺便推荐几个 Spring Boot 学习资料。 1.Spring Boot 是什么       我们刚开始学习 JavaWeb 的时候,使用 Servlet/JSP 做开发,一个接口搞一个 Servlet ,很头大,后来我们通过隐藏域或者反射等方式,可以减少 Servlet 的创建,但是依然不方便。      再后来,我们引入 Struts2/SpringMVC 这一类的框架,来简化我们的开发 ,和 Servlet/JSP 相比,引入框架之后,生产力确实提高了不少,但是用久了,又发现了新的问题,即配置繁琐易出错,要做一个新项目,先搭建环境,环境搭建来搭建去,就是那几行配置,不同的项目,可能就是包不同,其他大部分的配置都是一样的。      Java 总是被人诟病配置繁琐代码量巨大,这就是其中一个表现。那么怎么办?Spring Boot 应运而生,Spring Boot 是 Pivotal 团队在 2013 年开始研发的一个基于 Spring 的全新框架,试图将 Spring 中臃肿的配置进行简化,使 Java 开发更加轻量与快速,这个框架非常活跃,官方也非常重视。 Spring Boot 主要提供了如下功能:1. 为所有基于 Spring 的 Java 开发提供方便快捷的入门体验。2. 开箱即用,有自己自定义的配置就是用自己的,没有就使用官方提供的默认的。3. 提供了一系列通用的非功能性的功能,例如嵌入式服务器、安全管理、健康检测等。4. 绝对没有代码生成,也不需要XML配置。      Spring Boot 的出现让 Java 开发又回归简单,因为确确实实解决了开发中的痛点,因此这个技术得到了非常广泛的使用,大概从 2017 年年初开始,Spring Boot 基本上面试必问,现在流行的 Spring Cloud 微服务也是基于 Spring Boot,因此,所有的 Java 工程师都有必要掌握好 Spring Boot。从 Spring Boot 诞生的过程中,我们可以看到:1. Spring Boot 并非另起炉灶,而是在现有的 Spring 框架的基础上整出来的,它把 Spring 中繁琐的配置进行了简化。2. Spring Boot 降低了 Spring 家族的使用门槛,使新手更易上手 Spring 框架。      既然 Spring Boot 不是另起炉灶,那么 Spring Boot 学习要不要跳过 SSM 呢?听松哥来分析。 2.要不要跳过 SSM      这是很多人问我的一个问题,我的建议是:【不要】。      Spring Boot 基于 Spring,简单且容易上手,很多人想当然的跳过 SSM 直接上 Spring Boot。但是当我们细究 Spring Boot 中的自动化配置、条件注解、Java 配置等东西时,实在找不出太多新鲜玩意,Java 配置是 Spring3 开始提供的,条件注解 也是 Spring 中的东西,很多很多,都是 Spring 中就有的,只不过这些东西在 Spring Boot 时代大放异彩。      也就是说,即使你跳过了 SSM 直接去学习 Spring Boot,实际上还是在学习 Spring 中的东西,那既然这样,我们还不如坐下来,老老实实把 Spring 过一遍。      各个领域的开发工程师其实都会面临类似的问题,学习了一些优秀的封装框架之后,还有没有必要去学习底层?当然有必要!因为底层的东西可以让你深刻的理解你目前用的这个东西,也能让你在出问题时快速解决掉问题。      其实无论你想搞什么技术,都要有牢固的基础知识,这些牢固的基础知识就像肥沃的土壤,可以孕育出各种不同技术方向的牛人,基础掌握好了,学什么框架都快。今天你跳过 SSM 直接学了 Spring Boot,假如有一天 Spring Boot 不行了,Pivotal 团队又基于 Spring 框架搞了一个新的框架出来,那你是不是又要去学一遍?但是如果你一开始就掌握了 Spring 的各种用法,无论基于它搞出来什么样的框架,你都能快速上手。更进一步,如果你研究透了 Spring 中的 AOP、Ioc/DI,你会发现很多框架大同小异,核心思想就是这些东西,那么你在学习 Spring 之外的框架,就会容易很多。      **如果你对 SSM 还不太熟悉的话,可以在松哥公号(江南一点雨)后台分别回复 `spring`、`springmvc`、`mybatis` 获取松哥手敲 5 万余字的干货教程。** 3.都要学哪些       那么 Spring Boot 学习都要学哪些东西呢?我这里列举了一个进阶路线:1. 最基础的当然是 Spring/SpringMVC 相关的东西了。2. 搭配各种页面模版的使用,例如 Jsp/Thymeleaf/Freemarker/Groovy Templates 等。3. 和各种 SQL 数据库的整合,以及一些常见的数据持久化框架,例如 JdbcTemplate、MyBatis、Jpa 等。4. 和各种 NoSQL 数据库的整合,例如 Redis、MongoDB、Elasticsearch 等。5. 搭配安全管理相关的知识点,例如 Spring Security、Shiro 等。6. 缓存的使用,例如 JCache、Ehcache 等。7. 和消息中间件的搭配整合,如 ActiveMQ、RabbitMQ、Kafka 等。8. 数据校验/定时任务/邮件发送等。9. 各种监控的使用。10. 结合 WebSocket 的使用。11. Spring Cloud 中相关组件。12. ...      上面这些只是我列出来的一些比较常见的技术点,每个技术点都还可以延伸出很多其他的东西,大家可以结合自己的情况,按照顺序一个一个来学,这里边还涉及到很多第三方的框架,例如 Redis、MongoDB、RabbitMQ 等,Spring Boot 的出现只是让这些组件在和 Spring 家族的产品整合时变得更加方便,但是并不会简化这些组件原本的用法,所以,该学 Redis、该学 MongoDB、该学 RabbitMQ 等等,还是一个不能少。以 Redis 为例,学会了 Redis,学会了 Spring 整合 Redis,再回过头来看 Spring Boot 整合 Redis,那简直太 easy 了(**大家在公众号后台回复 redis,有松哥手敲的 redis 教程**)。      当然,学习 Spring Boot 最终我们还是奔着快速开发和微服务去的,所以,像 Docker、Spring Cloud 等技术,也是需要去了解一下的。 4.怎么学       Spring Boot 发展到今天,网上的资料和图书现在是越来越多了。在看资料学习的同时,大家也要留意以下几个点:1. 多看源码。不同于其他全新的框架源码你可能会看懵了,由于 Spring Boot 是基于 Spring 的,所以只要你 Spring 基础扎实,看 Spring Boot 源码可以说是毫无压力。如果看 Spring Boot 源码觉得有压力,那可能你 Spring 基础不牢靠,这个时候不妨放下 Spring Boot,去复习下 Spring。2. 每当学会 Spring Boot 中的一个知识点,不妨想想这个功能在 Spring 框架中要如何使用,如何配置,两边都搞懂了,互相印证,加深对一个知识点的理解。3. 多多关注 Spring Boot 的发展动态。不同于传统的框架可能一年更新一两次,Spring Boot 更新非常频繁,二次每次更新都会带来一些好玩的东西,可能会有新的 API 加入进来,也可能会有旧的 API 失效,变化大,因此多多关注,避免掉坑。      最后,我这里给大家列举几个我自己经常关注的几个资源。 4.1 官方文档       老实说,Spring Boot 的官方文档是我接触的所有官方文档中最条理清晰浅显易懂的,大家做开发,多多少少都接触过一些第三方的开放平台,很多平台的文档真是让人忍不住想吐槽,框架都做出来了,认认真真写个文档有那么难么?      不过 Spring Boot 的官方文档可以算是非常非常友好了。虽然是英文的,但是实际上对英文要求并不高,连读带猜,其实很容易明白它的含义,我一般对 Spring Boot 中某个知识点有疑问的时候,都是首选官方文档,当前最新版的官方文档地址是:- https://docs.spring.io/spring-boot/docs/2.2.4.RELEASE/reference/html      当然,如果你嫌官方文档打开慢,松哥也帮你下载好了最新版的 pdf,公众号后台回复 `springboot2.2.4` 可以获取。 4.2 Spring 官方博客       每次 Spring 或者 Spring Boot 发新版本,松哥都会去看一下新版本有哪些好玩的东西,增加了哪些内容。我不可能把源码读一遍然后总结出来它的变化,那一般是如何获取权威的第一手信息呢?关注 Spring 官方博客即可。      打开 Spring 官网,在顶部菜单里有一个选项就是 Blog,关于 Spring 家族产品的任何更新计划,更新结果,都会在这里通知到大家。             松哥也推荐大家多多关注这个 Blog,一方面能够及时接收到一手信息,另一方面还能提高英语,一举两得。宅在家,泡一壶茶,细细的品一品这个网站,真的蛮不错。      Blog 地址:- https://spring.io/blog  4.3 中文资料       说到中文资料,就不得不说松哥自己的在线教程和离线 pdf 文档了。手敲了 274 页教程,囊括了 Spring Boot2 常见的各种用法,即有离线的 pdf 供大家下载,也有在线的学习网站,这就是满满的诚意,还没下载 pdf 的小伙伴不要错过。       在线教程地址:- http://springboot.javaboy.org      离线 pdf 下载文档,在公众号后台回复 springboot 获取百度网盘地址。 4.4 学习案例       除了这些文字性的东西之外,一些在线案例也至关重要。这里给大家推荐两个仓库,这两个仓库中的所有案例都是基于 Spring Boot2 来做的。      首先就是我公众号上文章的配套案例:      GitHub 地址:https://github.com/lenve/javaboy-code-samples      Gitee 地址:https://gitee.com/lenve/javaboy-code-samples      这个仓库中的大部分案例都是针对 Spring Boot 的,而且有一个好处就是这些案例都有对应的讲解文章,每个案例都对应一个文章,岂不美哉。       另一个仓库就是我整理的比较完善的一个仓库,但是就没有对应的讲解文章了:      GitHub 地址:https://github.com/lenve/javaboy-video-samples      Gitee 地址:https://gitee.com/lenve/javaboy-video-samples 5.小结       资料贵精不贵多,关键是要动手去学。大学时候,有的同学热衷于收集各种资料,电脑硬盘塞得满满的,但是就是不学,这些资料再多也没有用。      当然,如果大家对松哥自己录制的 Spring Boot+Vue+微人事+Spring Cloud 视频教程感兴趣,也可以看看这篇文章:[Spring Boot + Vue 视频教程喜迎大结局,西交大的老师竟然都要来一套!](https://mp.weixin.qq.com/s/8FmgtWyz6HUIbF4smXQOwQ),或者加下面的微信咨询。关于作者   王松,江湖人称“松哥”出书《Spring Boot +Vue全栈开发实战》,清华大学出版社个人公众号:“江南一点雨”,2019年产出117篇原创技术干货,包含“Spring Boot系列”、“前后端分离系列”、“系列教程等”联系作者添加好友时麻烦请备注来源、公司及名称,谢谢HDZ社区—携手全球开发者 共建开放、创新、多元的开发者社区组织       HDZ是Huawei Developers Zone的英文缩写,是华为开发者生态面向全球开发者建立开放、创新、多元的开发者社区组织。      致力于帮助开发者学习提升、互动交流、挖掘机会,推动ICT、互联网等产业生态的建立和发展。      对云计算、IoT、人工智能、5G、区块链、鲲鹏、昇腾、软件开发与运维、开源等各技术领域感兴趣的开发者、软件工程师、创业者、运营人、产品人、大学生、老师等都可以参与到HDZ。      HDZ秉承开放、创新、多元的社区文化,完全由各地HDZ组织者、志愿者自发组建和领导。华为公司不直接参与HDZ组织建设和领导,只按需对HDZ社区活动提供必要的方向指导、资源支持、活动支撑等,并为各地HDZ组织者提供与全国组织者互动交流的机会。
  • 【求助】cse-solution-spring-cloud 有2.3.58升级到2.3.73服务注册不上问题
    升级版本com.huawei.paas.cse2.3.58--2.3.73    项目springcloud Greenwich.SR1  sprongboot2.1.6 问题发生由于org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader] to type [java.lang.String]at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.core.env.AbstractPropertyResolver.convertValueIfNecessary(AbstractPropertyResolver.java:263) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:91) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:62) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:539) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.cloud.netflix.archaius.ConfigurableEnvironmentConfiguration.getProperty(ConfigurableEnvironmentConfiguration.java:64) ~[spring-cloud-netflix-archaius-2.1.1.RELEASE.jar:2.1.1.RELEASE]at com.netflix.config.ConcurrentCompositeConfiguration.getProperty(ConcurrentCompositeConfiguration.java:539) ~[archaius-core-0.7.6.jar:0.7.6]at com.netflix.config.ConcurrentCompositeConfiguration.getProperty(ConcurrentCompositeConfiguration.java:539) ~[archaius-core-0.7.6.jar:0.7.6]at org.apache.servicecomb.config.ConfigUtil.getProperty(ConfigUtil.java:92) ~[foundation-config-1.2.0.B011.jar:1.2.0.B011]at org.apache.servicecomb.config.ConfigUtil.getProperty(ConfigUtil.java:86) ~[foundation-config-1.2.0.B011.jar:1.2.0.B011]at org.apache.servicecomb.config.ConfigUtil.getMicroserviceConfigLoader(ConfigUtil.java:102) ~[foundation-config-1.2.0.B011.jar:1.2.0.B011]at org.apache.servicecomb.serviceregistry.RegistryUtils.init(RegistryUtils.java:61) ~[service-registry-1.2.0.B011.jar:1.2.0.B011]at org.apache.servicecomb.springboot.starter.registry.RegistryIntializer.initRegistry(RegistryIntializer.java:39) ~[spring-boot-starter-registry-1.2.0.B011.jar:1.2.0.B011]at org.apache.servicecomb.springboot.starter.registry.ServiceCenterRegistryConfiguration.<init>(ServiceCenterRegistryConfiguration.java:30) ~[spring-boot-starter-registry-1.2.0.B011.jar:1.2.0.B011]at org.apache.servicecomb.springboot.starter.registry.ServiceCenterRegistryConfiguration$$EnhancerBySpringCGLIB$$9de1b9ba.<init>(<generated>) ~[spring-boot-starter-registry-1.2.0.B011.jar:1.2.0.B011]at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0_191]at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[?:1.8.0_191]at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:1.8.0_191]at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[?:1.8.0_191]at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:172) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1295) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1197) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) [spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) [spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845) [spring-beans-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) [spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) [spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]at org.springframework.boot.SpringApplication.run(SpringApplication.java:311) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]at com.huawei.routeserver.RouteServerApplication.main(RouteServerApplication.java:39) [classes/:?]
  • [问题求助] CSE可以和spring cloud stream 兼容吗
    加上EnableBinding注解后,启动报端口占用错误猜测是先启动了vertx rest的端口后面再启动spring的tomcat的时候报错了下面是pom和父pom4.0.0com.huawei.aciotparent1.0-SNAPSHOTdevice-common0.0.1-SNAPSHOTdevice-commonDemo project for Spring Boot1.8org.projectlomboklomboktrueorg.apache.servicecombhandler-tracing-zipkinorg.springframework.cloudspring-cloud-stream-test-supporttestorg.springframework.cloudspring-cloud-streamorg.springframework.cloudspring-cloud-stream-binder-kafkaorg.springframework.kafkaspring-kafkacom.huawei.eciotcore-util0.0.1-SNAPSHOT父pomorg.springframework.bootspring-boot-starter-parent2.1.6.RELEASEpomimportorg.springframeworkspring-core5.1.8.RELEASEpomimportcom.huawei.paas.csecse-dependency-spring-boot26.5.62pomimportcom.huawei.paas.csecse-solution-service-engineorg.slf4jslf4j-log4j12org.apache.servicecombspring-boot2-starter-servletorg.springframework.bootspring-boot-starter-testtestyaml:   :     : device-common :   : 8090   :     : /device-north : ac-iot :   : device   : 0.0.1             :     : true   : development :   :     :       : false   :     : 192.188.240.32:${server.port}   :     : /device   :     :       : http://192.88.16.46:30100      :   :     :       :         : loadbalance,tracing-consumer       :         : tracing-provider   :     :       : http://localhost:9411大佬们帮忙看一下是哪里配错了吗
  • [问题求助] Spring Boot工程microservice.yaml中servicecomb.datacenter.availableZone无法替换问题
    Spring Boot工程将microservice.yaml文件打到了jar包中,servicecomb.datacenter.availableZone需要在服务启动前替换,jar包内的文件无法修改,az的值又不可以写成环境变量,求助可以怎么解决这个问题?
  • [交流分享] 华为云服务器布置spring boot项目
    化鲲为鹏,我有话说总结自己在云服务器上布置spring boot项目,可以简单的分为三个步骤:1.安装环境;2.上传jar/war项目;3.运行。安装环境a.下载Java(这里下载的是jdk8),通过wget命令wget http://mirrors.linuxeye.com/jdk/jdk-8u144-linux-x64.tar.gzb.解压(这里的目录是 /home/vcc/java)tar xzf jdk-8u144-linux-x64.tar.gz -C /home/vcc/javac.设置环境变量编辑/etc/profile文件:sudo vi /etc/profile进入编辑模式后在最后添加如下信息:#set java environmentexport JAVA_HOME=/home/vcc/java/jdk1.8.0_144export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/libexport PATH=$JAVA_HOME/bin:$PATH保存后退出,加载环境变量:source /etc/profile  2.上传jar包打包spring boot项目,通过xshell连接云服务器,将jar包上传至一个文件夹  3.运行通过命令(nohup的目的是让jar包在服务器上运行)$ nohup java -jar test.jar &   
  • [技术干货] ActFramework 入门指南——Controller 与 Action
    AppEntry 这个启动类本身就是一个 Controller。 ActFramework 的 Controller 不要求标注任何注解,也不要求继承或实现任何一个类。 只要 Controller 含有 Action,那么它就是一个 Controller 。(这时作者说的,但是我也不知道含有拦截器的算不算Controller,但是问题不大,这个并不影响)让我们来关注一下 AppEntry 的 home 方法。@GetActionpublic void home(@DefaultValue("World") @Output String who) { }方法不长,但是却是一个非常标准的 Action 。 @GetAction 注解 代表了 这是一个 Get 方法。 同理还有 @PostAction 、 @PutAction 、 @DeleteAction 。 还有一个 @Action 注解,用来定义全部或指定 HTTP 请求方法的路由。 @DefaultValue 代表了 当 who 为 null 时的默认值。 @Output 则代表了这个参数会被带到模板。用过 Spring 的同学可能可以理解 who 变量具体的含义,以及值来源。 这里简要的解释一下 who 变量的值来源。 在 Action 方法参数内的变量,一般会被匹配请求参数。 如变量名为 who 则会匹配 名为 who 的请求参数。 不信邪的同学可以尝试访问下 http://127.0.0.1:5460/?who=ActFramework 来验证下结果。当然,参数不仅仅能用String,还可以使用Integer 等等,以及可以使用Java 实体类。 ActFramework 会根据请求头来区分请求内容。表单请求,或是 application/json 又或者是其他什么,一视同仁。 不需要 @RequestBody 。同时,ActFramework 支持匹配url路径,让我们写一个简单的 Action 。@GetAction("test/{name}")public String test(String name){    return name; }Spring 的同学可能会非常感动,终于不用写烦人的@PathVariable了! 同时 ActFramework 会根据你方法的返回值类型来确定该怎样渲染页面。 如果你的方法是 void 的,ActFramework 则会自动去寻找模版文件。 如果是其他类型,ActFramework 则会选择一个合适的方式将你的返回值渲染出去。 也就是说,我们也不再需要 @ResponseBody 了!此时,先不要着急点击你的重启按钮,直接访问下 http://127.0.0.1:5460/test/wow 试试! 是不是wow! ActFramework 的 热加载 完全不需要你进行任何操作(虽然我还是会习惯性的点一下重启)。 你只需要编码 然后 查看结果就好啦。使用 Spring 的同学可能会非常感动,终于不用等一两分钟的重启时间了。 这时候要吐槽一下,IDEA启动 build 项目,加上启动 Tomcat 最后算上 Spring 启动,我的天啊,这个启动时间。 有了Spring Boot 之后稍微改善了一点,项目一大,启动还是得一分多钟,改一点一分钟,改一点一分钟,工作效率就是在这没得。有些同学可能想说,单单这些,也不全够啊。 有些时候还是需要 Request 和 Response 啊。别急,你在方法的参数里面写上 H.Request 和 H.Response 就行了。 其实在 Http协议 下,大家都差不多。 这块我就不复制了,建议直接查看文档(在Gitee的,方便国内的同学查看)。同时 ActFramework 提供了很多非常方便的方法。 如:  大家可以选择 import static act.controller.Controller.Util.*; 或者 Controller extends Controller.Util 来食用。 当然你也可以选择不用。
  • [技术干货] 方志朋-SpringCloud系列:Spring Cloud Consul 之Greenwich版本全攻略-2
    微服务架构是一个分布式架构,微服务系统按业务划分服务单元,一个微服务系统往往有很多个服务单元。由于服务单元数量众多,业务的复杂性较高,如果出现了错误和异常,很难去定位。主要体现在一个请求可能需要调用很多个服务,而内部服务的调用复杂性决定了问题难以定位。所以在微服务架构中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每个请求的步骤清晰可见,出了问题能够快速定位的目的。                  在微服务系统中,一个来自用户的请求先到达前端A(如前端界面),然后通过远程调用,到达系统的中间件B、C(如负载均衡、网关等),最后到达后端服务D、E,后端经过一系列的业务逻辑计算,最后将数据返回给用户。对于这样一个请求,经历了这么多个服务,怎么样将它的请求过程用数据记录下来呢?这就需要用到服务链路追踪。Spring Cloud SleuthSpring Cloud Sleuth 为服务之间调用提供链路追踪。通过Sleuth 可以很清楚的了解到一个服务请求经过了哪些服务,每个服务处理花费了多长。从而让我们可以很方便的理清各微服务间的调用关系。此外Sleuth 可以帮助我们:§ 耗时分析: 通过Sleuth 可以很方便的了解到每个采样请求的耗时,从而分析出哪些服务调用比较耗时;§ 可视化错误: 对于程序未捕捉的异常,可以通过集成Zipkin 服务界面上看到;§ 链路优化: 对于调用比较频繁的服务,可以针对这些服务实施一些优化措施。Google开源了Dapper链路追踪组件,并在2010年发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,这篇论文是业内实现链路追踪的标杆和理论基础,具有很高的参考价值。Spring Cloud Sleuth采用了Google的开源项目Dapper的专业术语。§ Span:基本工作单元,发送一个远程调度任务就会产生一个Span,Span是用一个64位ID唯一标识的,Trace是用另一个64位ID唯一标识的。Span还包含了其他的信息,例如摘要、时间戳事件、Span的ID以及进程ID。§ Trace:由一系列Span组成的,呈树状结构。请求一个微服务系统的API接口,这个API接口需要调用多个微服务单元,调用每个微服务单元都会产生一个新的Span,所有由这个请求产生的Span组成了这个Trace。§ Annotation:用于记录一个事件,一些核心注解用于定义一个请求的开始和结束,这些注解如下。o   cs-Client Sent:客户端发送一个请求,这个注解描述了Span的开始。o   sr-Server Received:服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳,便可得到网络传输的时间。o   ss-Server Sent:服务端发送响应,该注解表明请求处理的完成(当请求返回客户端),用ss的时间戳减去sr时间戳,便可以得到服务器请求的时间。o   cr-Client Received:客户端接收响应,此时Span结束,如果cr的时间戳减去cs时间戳,便可以得到整个请求所消耗的时间。Spring Cloud Sleuth 也为我们提供了一套完整的链路解决方案,Spring Cloud Sleuth 可以结合Zipkin,将信息发送到Zipkin,利用Zipkin 的存储来存储链路信息,利用Zipkin UI 来展示数据。ZipkinZipkin是一种分布式链路追踪系统。它有助于收集解决微服务架构中的延迟问题所需的时序数据。它管理这些数据的收集和查找。Zipkin的设计基于Google Dapper论文。跟踪器存在于应用程序中,记录请求调用的时间和元数据。跟踪器使用库,它们的使用对用户是无感知的。例如,Web服务器会在收到请求时和发送响应时会记录相应的时间和一些元数据。一次完整链路请求所收集的数据被称为Span。我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API 接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。除了面向开发的API 接口之外,它也提供了方便的UI 组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。Zipkin 提供了可插拔数据存储方式:In-Memory、MySql、Cassandra 以及Elasticsearch。接下来的测试为方便直接采用In-Memory 方式进行存储,生产推荐Elasticsearch.上图展示了Zipkin 的基础架构,它主要由4 个核心组件构成:§ Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为Zipkin 内部处理的Span 格式,以支持后续的存储、分析、展示等功能。§ Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中。§ RESTful API:API 组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接系统访问以实现监控等。§ Web UI:UI 组件,基于API 组件实现的上层应用。通过UI 组件用户可以方便而有直观地查询和分析跟踪信息。案例实战在本案例一共有三个应用,分别为注册中心,eureka-server、eureka-client、eureka-client-feign,三个应用的基本信息如下:应用名端口作用eureka-server8761注册中心eureka-client8763服务提供者eureka-client-feign8765服务消费者其中eureka-server 应用为注册中心,其他两个应用向它注册。eureka-client为服务提供者,提供了一个RESTAPI,eureka-client-feign为服务消费者,通过Feign Client向服务提供者消费服务。在之前的文章已经讲述了如何如何搭建服务注册中心,在这里就省略这一部分内容。服务提供者提供一个REST接口,服务消费者通过FeignClient消费服务。服务提供者eureka-client服务提供者,对外提供一个RESTAPI,并向服务注册中心注册,这部分内容,不再讲述,见源码。需要在工程的pom文件加上sleuth的起步依赖和zipkin的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-sleuth</artifactId>4.  </dependency>5.  <dependency>6.      <groupId>org.springframework.cloud</groupId>7.      <artifactId>spring-cloud-starter-zipkin</artifactId>8.  </dependency>在工程的配置文件application.yml需要做以下的配置:1.  spring:2.    sleuth:3.      web:4.        client:5.          enabled:true6.      sampler:7.        probability:1.0 # 将采样比例设置为1.0,也就是全部都需要。默认是0.18.    zipkin:9.      base-url:http://localhost:9411/ # 指定了Zipkin 服务器的地址其中spring.sleuth.web.client.enable为true设置的是web开启sleuth功能;spring.sleuth.sampler.probability可以设置为小数,最大值为1.0,当设置为1.0时就是链路数据100%收集到zipkin-server,当设置为0.1时,即10%概率收集链路数据;spring.zipkin.base-url设置zipkin-server的地址。对外提供一个Api,代码如下:1.  @RestController2.  publicclassHiController{3.    4.      @Value("${server.port}")5.      Stringport;6.      @GetMapping("/hi")7.      publicStringhome(@RequestParamStringname){8.          return"hi "+name+",i am from port:"+port;9.      }10.   11.  }服务消费者服务消费者通过FeignClient消费服务提供者提供的服务。同服务提供者一样,需要在工程的pom文件加上sleuth的起步依赖和zipkin的起步依赖,另外也需要在配置文件application.yml做相关的配置,具体同服务提供者。服务消费者通过feignClient进行服务消费,feignclient代码如下:1.  @FeignClient(value ="eureka-client",configuration =FeignConfig.class)2.  publicinterfaceEurekaClientFeign{3.    4.      @GetMapping(value ="/hi")5.      StringsayHiFromClientEureka(@RequestParam(value ="name")Stringname);6.  }servcie层代码如下:1.  @Service2.  publicclassHiService{3.    4.      @Autowired5.      EurekaClientFeigneurekaClientFeign;6.    7.    8.      publicStringsayHi(Stringname){9.          return eurekaClientFeign.sayHiFromClientEureka(name);10.      }11.  }controller代码如下:1.  @RestController2.  publicclassHiController{3.      @Autowired4.      HiServicehiService;5.    6.      @GetMapping("/hi")7.      publicStringsayHi(@RequestParam(defaultValue ="forezp",required =false)Stringname){8.          returnhiService.sayHi(name);9.      }上面的代码对外暴露一个API,通过FeignClient的方式调用eureka-client的服务。zipkin-server在Spring Cloud D版本,zipkin-server通过引入依赖的方式构建工程,自从E版本之后,这一方式改变了,采用官方的jar形式启动,所以需要通过下载官方的jar来启动,也通过以下命令一键启动:1.  curl -sSL https://zipkin.io/quickstart.sh | bash -s2.  java -jar zipkin.jar上面的第一行命令会从zipkin官网下载官方的jar包。如果是window系统,建议使用gitbash执行上面的命令。如果用Docker 的话,使用以下命令:1.  docker run -d -p 9411:9411openzipkin/zipkin通过java -jar zipkin.jar的方式启动之后,在浏览器**问lcoalhost:9411,显示的界面如下:链路数据验证依次启动eureka-server,eureka-client,eureka-client-feign的三个应用,等所有应用启动完成后,在浏览器**问http://localhost:8765/hi(如果报错,是服务与发现需要一定的时间,耐心等待几十秒),访问成功后,再次在浏览器**问zipkin-server的页面,显示如下:从上图可以看出每次请求所消耗的时间,以及一些span的信息。从上图可以看出具体的服务依赖关系,eureka-feign-client依赖了eureka-client。使用rabbitmq进行链路数据收集在上面的案例中使用的http请求的方式将链路数据发送给zipkin-server,其实还可以使用rabbitmq的方式进行服务的消费。使用rabbitmq需要安装rabbitmq程序,下载地址http://www.rabbitmq.com/。下载完成后,需要eureka-client和eureka-client-feign的起步依赖加上rabbitmq的依赖,依赖如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-stream-binder-rabbit</artifactId>4.  </dependency>在配置文件上需要配置rabbitmq的配置,配置信息如下:1.  spring:2.    rabbitmq:3.      host:localhost4.      username:guest5.      password:guest6.      port:5672另外需要把spring.zipkin.base-url去掉。在上面2个工程中,rabbitmq通过发送链路数据,那么zipkin-server是怎么样知道rabbitmq的地址呢,怎么监听收到的链路数据呢?这需要在程序启动的时候,通过环境变量的形式到环境中,然后zikin-server从环境变量中读取。可配置的属性如下:属性环境变量描述zipkin.collector.rabbitmq.addressesRABBIT_ADDRESSES用逗号分隔的RabbitMQ 地址列表,例如localhost:5672,localhost:5673zipkin.collector.rabbitmq.passwordRABBIT_PASSWORD连接到RabbitMQ 时使用的密码,默认为guestzipkin.collector.rabbitmq.usernameRABBIT_USER连接到RabbitMQ 时使用的用户名,默认为guestzipkin.collector.rabbitmq.virtual-hostRABBITVIRTUALHOST使用的RabbitMQ virtual host,默认为/zipkin.collector.rabbitmq.use-sslRABBITUSESSL设置为true则用SSL 的方式与RabbitMQ 建立链接zipkin.collector.rabbitmq.concurrencyRABBIT_CONCURRENCY并发消费者数量,默认为1zipkin.collector.rabbitmq.connection-timeoutRABBITCONNECTIONTIMEOUT建立连接时的超时时间,默认为60000毫秒,即1 分钟zipkin.collector.rabbitmq.queueRABBIT_QUEUE从中获取span 信息的队列,默认为zipkin比如,通过以下命令启动:1.  RABBIT_ADDRESSES=localhost java-jar zipkin.jar上面的命令等同于一下的命令:1.  java -jar zipkin.jar --zipkin.collector.rabbitmq.addressed=localhost用上面的2条命令中的任何一种方式重新启动zipkin-server程序,并重新启动eureka-client、eureka-server、eureka-client-feign,动完成后在浏览器**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,就可以看到通过Http方式发送链路数据一样的接口。自定义Tag在页面上可以查看每个请求的traceId,每个trace又包含若干的span,每个span又包含了很多的tag,自定义tag可以通过Tracer这个类来自定义。1.  @Autowired2.  Tracertracer;3.    4.   @GetMapping("/hi")5.      publicStringhome(@RequestParamStringname){6.          tracer.currentSpan().tag("name","forezp");7.          return"hi "+name+",i am from port:"+port;8.      }将链路数据存储在Mysql数据库中上面的例子是将链路数据存在内存中,只要zipkin-server重启之后,之前的链路数据全部查找不到了,zipkin是支持将链路数据存储在mysql、cassandra、elasticsearch中的。现在讲解如何将链路数据存储在Mysql数据库中。首先需要初始化zikin存储在Mysql的数据的scheme,可以在这里查看https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql,具体如下:1.  CREATE TABLE IF NOT EXISTS zipkin_spans (2.    `trace_id_high`BIGINT NOT NULL DEFAULT 0COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',3.    `trace_id`BIGINT NOT NULL,4.    `id`BIGINT NOT NULL,5.    `name`VARCHAR(255)NOT NULL,6.    `parent_id`BIGINT,7.    `debug`BIT(1),8.    `start_ts`BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',9.    `duration`BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query'10.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;11.   12.  ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`,`trace_id`,`id`)COMMENT 'ignore insert on duplicate';13.  ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`,`trace_id`,`id`)COMMENT 'for joining with zipkin_annotations';14.  ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`,`trace_id`)COMMENT 'for getTracesByIds';15.  ALTER TABLE zipkin_spans ADD INDEX(`name`)COMMENT 'for getTraces and getSpanNames';16.  ALTER TABLE zipkin_spans ADD INDEX(`start_ts`)COMMENT 'for getTraces ordering and range';17.   18.  CREATE TABLE IF NOT EXISTS zipkin_annotations (19.    `trace_id_high`BIGINT NOT NULL DEFAULT 0COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',20.    `trace_id`BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',21.    `span_id`BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',22.    `a_key`VARCHAR(255)NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',23.    `a_value`BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',24.    `a_type`INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',25.    `a_timestamp`BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',26.    `endpoint_ipv4`INT COMMENT 'Null when Binary/Annotation.endpoint is null',27.    `endpoint_ipv6`BINARY(16)COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',28.    `endpoint_port`SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',29.    `endpoint_service_name`VARCHAR(255)COMMENT 'Null when Binary/Annotation.endpoint is null'30.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;31.   32.  ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`)COMMENT 'Ignore insert on duplicate';33.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`,`trace_id`,`span_id`)COMMENT 'for joining with zipkin_spans';34.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`,`trace_id`)COMMENT 'for getTraces/ByIds';35.  ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`)COMMENT 'for getTraces and getServiceNames';36.  ALTER TABLE zipkin_annotations ADD INDEX(`a_type`)COMMENT 'for getTraces and autocomplete values';37.  ALTER TABLE zipkin_annotations ADD INDEX(`a_key`)COMMENT 'for getTraces and autocomplete values';38.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`,`span_id`,`a_key`)COMMENT 'for dependencies job';39.   40.  CREATE TABLE IF NOT EXISTS zipkin_dependencies (41.    `day`DATE NOT NULL,42.    `parent`VARCHAR(255)NOT NULL,43.    `child`VARCHAR(255)NOT NULL,44.    `call_count`BIGINT,45.    `error_count`BIGINT46.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;47.   48.  ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`,`parent`,`child`);在数据库中初始化上面的脚本之后,需要做的就是zipkin-server如何连接数据库。zipkin如何连数据库同连接rabbitmq一样。zipkin连接数据库的属性所对应的环境变量如下:属性环境变量描述zipkin.torage.typeSTORAGE_TYPE默认的为mem,即为内存,其他可支持的为cassandra、cassandra3、elasticsearch、mysqlzipkin.torage.mysql.hostMYSQL_HOST数据库的host,默认localhostzipkin.torage.mysql.portMYSQLTCPPORT数据库的端口,默认3306zipkin.torage.mysql.usernameMYSQL_USER连接数据库的用户名,默认为空zipkin.torage.mysql.passwordMYSQL_PASS连接数据库的密码,默认为空zipkin.torage.mysql.dbMYSQL_DBzipkin使用的数据库名,默认是zipkinzipkin.torage.mysql.max-activeMYSQLMAXCONNECTIONS最大连接数,默认是101.  STORAGE_TYPE=mysql MYSQL_HOST=localhost MYSQL_TCP_PORT=3306MYSQL_USER=root MYSQL_PASS=123456MYSQL_DB=zipkin java -jar zipkin.jar等同于以下的命令1.  java -jar zipkin.jar --zipkin.torage.type=mysql --zipkin.torage.mysql.host=localhost --zipkin.torage.mysql.port=3306--zipkin.torage.mysql.username=root --zipkin.torage.mysql.password=123456使用上面的命令启动zipkin.jar工程,然后再浏览数**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,可以看到链路数据。这时去数据库查看数据,也是可以看到存储在数据库的链路数据,如下:这时重启应用zipkin.jar,再次在浏览器**问http://localhost:9411/zipkin/,仍然可以得到之前的结果,证明链路数据存储在数据库中,而不是内存中。将链路数据存在在Elasticsearch中zipkin-server支持将链路数据存储在ElasticSearch中。读者需要自行安装ElasticSearch和Kibana,下载地址为https://www. elastic.co/products/elasticsearch。安装完成后启动,其中ElasticSearch的默认端口号为9200,Kibana的默认端口号为5601。同理,zipkin连接elasticsearch也是从环境变量中读取的,elasticsearch相关的环境变量和对应的属性如下:属性环境变量描述zipkin.torage.elasticsearch.hostsES_HOSTSES_HOSTS,默认为空zipkin.torage.elasticsearch.pipelineES_PIPELINEES_PIPELINE,默认为空zipkin.torage.elasticsearch.max-requestsESMAXREQUESTSESMAXREQUESTS,默认为64zipkin.torage.elasticsearch.timeoutES_TIMEOUTES_TIMEOUT,默认为10szipkin.torage.elasticsearch.indexES_INDEXES_INDEX,默认是zipkinzipkin.torage.elasticsearch.date-separatorESDATESEPARATORESDATESEPARATOR,默认为“-”zipkin.torage.elasticsearch.index-shardsESINDEXSHARDSESINDEXSHARDS,默认是5zipkin.torage.elasticsearch.index-replicasESINDEXREPLICASESINDEXREPLICAS,默认是1zipkin.torage.elasticsearch.usernameES_USERNAMEES的用户名,默认为空zipkin.torage.elasticsearch.passwordES_PASSWORDES的密码,默认是为空采用以下命令启动zipkin-server:1.  STORAGE_TYPE=elasticsearch ES_HOSTS=http://localhost:9200 ES_INDEX=zipkin java -jar zipkin.jar1.  java -jar zipkin.jar --STORAGE_TYPE=elasticsearch --ES_HOSTS=http://localhost:9200 --ES_INDEX=zipkin 1.  java -jar zipkin.jar --STORAGE_TYPE=elasticsearch --ES_HOSTS=http://localhost:9200 --ES_INDEX=zipkin 1.  java -jar zipkin.jar --zipkin.torage.type=elasticsearch --zipkin.torage.elasticsearch.hosts=http://localhost:9200 --zipkin.torage.elasticsearch.index=zipkin 启动完成后,然后在浏览数**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,可以看到链路数据。这时链路数据存储在ElasticSearch。在zipkin上展示链路数据链路数据存储在ElasticSearch中,ElasticSearch可以和Kibana结合,将链路数据展示在Kibana上。安装完成Kibana后启动,Kibana默认会向本地端口为9200的ElasticSearch读取数据。Kibana默认的端口为5601,访问Kibana的主页http://localhost:5601,其界面如下图所示。在上图的界面中,单击“Management”按钮,然后单击“Add New”,添加一个index。我们将在上节ElasticSearch中写入链路数据的index配置为“zipkin”,那么在界面填写为“zipkin-*”,单击“Create”按钮,界面如下图所示:创建完成index后,单击“Discover”,就可以在界面上展示链路数据了,展示界面如下图所示。参考资料https://zipkin.io/https://github.com/spring-cloud/spring-cloud-sleuthhttps://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.1.0.RELEASE/single/spring-cloud-sleuth.htmlhttps://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.ymlhttps://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sqlhttps://windmt.com/2018/04/24/spring-cloud-12-sleuth-zipkin/https://segmentfault.com/a/119000001569767http://www.cnblogs.com/JreeyQi/p/9336692.html原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud 
  • [技术干货] 方志朋-SpringCloud系列:Spring Cloud Consul 之Greenwich版本全攻略
    什么是ConsulConsul是HashiCorp公司推出的开源软件,使用GO语言编写,提供了分布式系统的服务注册和发现、配置等功能,这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格。Consul不仅具有服务治理的功能,而且使用分布式一致协议RAFT算法实现,有多数据中心的高可用方案,并且很容易和Spring Cloud等微服务框架集成,使用起来非常的简单,具有简单、易用、可插排等特点。使用简而言之,Consul提供了一种完整的服务网格解决方案。Consul具有以下的特点和功能§ 服务发现:Consul的客户端可以向Consul注册服务,例如api服务或者mysql服务,其他客户端可以使用Consul来发现服务的提供者。Consul支持使用DNS或HTTP来注册和发现服务。§ 运行时健康检查:Consul客户端可以提供任意数量的运行状况检查机制,这些检查机制可以是给定服务(“是Web服务器返回200 OK”)或本地节点(“内存利用率低于90%”)相关联。这些信息可以用来监控群集的运行状况,服务发现组件可以使用这些监控信息来路由流量,可以使流量远离不健康的服务。§ KV存储:应用程序可以将Consul的键/值存储用于任何需求,包括动态配置,功能标记,协调,领导者选举等。它采用HTTP API使其易于使用。§ 安全服务通信:Consul可以为服务生成和分发TLS证书,以建立相互的TLS连接。§ 多数据中心:Consul支持多个数据中心。这意味着Consul的用户不必担心构建额外的抽象层以扩展到多个区域。Consul原理每个提供服务的节点都运行了Consul的代理,运行代理不需要服务发现和获取配置的KV键值对,代理只负责监控检查。代理节点可以和一个或者多个Consul server通讯。Consul服务器是存储和复制数据的地方。服务器本身选出了领导者。虽然Consul可以在一台服务器上运行,但建议使用3到5,以避免导致数据丢失的故障情况。建议为每个数据中心使用一组Consul服务器。如果你的组件需要发现服务,可以查询任何Consul Server或任何Consul客户端,Consul客户端会自动将查询转发给Consul Server。需要发现其他服务或节点的基础架构组件可以查询任何Consul服务器或任何Consul代理。代理会自动将查询转发给服务器。每个数据中心都运行Consul服务器集群。发生跨数据中心服务发现或配置请求时,本地Consul服务器会将请求转发到远程数据中心并返回结果。术语§ Agent agent是一直运行在Consul集群中每个成员上的守护进程。通过运行consul agent 来启动。agent可以运行在client或者server模式。指定节点作为client或者server是非常简单的,除非有其他agent实例。所有的agent都能运行DNS或者HTTP接口,并负责运行时检查和保持服务同步。§ Client 一个Client是一个转发所有RPC到server的代理。这个client是相对无状态的。client唯一执行的后台活动是加入LAN gossip池。这有一个最低的资源开销并且仅消耗少量的网络带宽。§ Server 一个server是一个有一组扩展功能的代理,这些功能包括参与Raft选举,维护集群状态,响应RPC查询,与其他数据中心交互WAN gossip和转发查询给leader或者远程数据中心。§ DataCenter 虽然数据中心的定义是显而易见的,但是有一些细微的细节必须考虑。例如,在EC2中,多个可用区域被认为组成一个数据中心?我们定义数据中心为一个私有的,低延迟和高带宽的一个网络环境。这不包括访问公共网络,但是对于我们而言,同一个EC2中的多个可用区域可以被认为是一个数据中心的一部分。§ Consensus 在我们的文档中,我们使用Consensus来表明就leader选举和事务的顺序达成一致。由于这些事务都被应用到有限状态机上,Consensus暗示复制状态机的一致性。§ Gossip Consul建立在Serf的基础之上,它提供了一个用于多播目的的完整的gossip协议。Serf提供成员关系,故障检测和事件广播。更多的信息在gossip文档中描述。这足以知道gossip使用基于UDP的随机的点到点通信。§ LAN Gossip 它包含所有位于同一个局域网或者数据中心的所有节点。§ WAN Gossip 它只包含Server。这些server主要分布在不同的数据中心并且通常通过因特网或者广域网通信。§ RPC 远程过程调用。这是一个允许client请求server的请求/响应机制。                 让我们分解这张图并描述每个部分。首先,我们能看到有两个数据中心,标记为“1”和“2”。Consul对多数据中心有一流的支持并且希望这是一个常见的情况。在每个数据中心,client和server是混合的。一般建议有3-5台server。这是基于有故障情况下的可用性和性能之间的权衡结果,因为越多的机器加入达成共识越慢。然而,并不限制client的数量,它们可以很容易的扩展到数千或者数万台。同一个数据中心的所有节点都必须加入gossip协议。这意味着gossip协议包含一个给定数据中心的所有节点。这服务于几个目的:第一,不需要在client上配置server地址。发现都是自动完成的。第二,检测节点故障的工作不是放在server上,而是分布式的。这是的故障检测相比心跳机制有更高的可扩展性。第三:它用来作为一个消息层来通知事件,比如leader选举发生时。每个数据中心的server都是Raft节点集合的一部分。这意味着它们一起工作并选出一个leader,一个有额外工作的server。leader负责处理所有的查询和事务。作为一致性协议的一部分,事务也必须被复制到所有其他的节点。因为这一要求,当一个非leader得server收到一个RPC请求时,它将请求转发给集群leader。server节点也作为WAN gossip Pool的一部分。这个Pool不同于LAN Pool,因为它是为了优化互联网更高的延迟,并且它只包含其他Consul server节点。这个Pool的目的是为了允许数据中心能够以low-touch的方式发现彼此。这使得一个新的数据中心可以很容易的加入现存的WAN gossip。因为server都运行在这个pool中,它也支持跨数据中心请求。当一个server收到来自另一个数据中心的请求时,它随即转发给正确数据中想一个server。该server再转发给本地leader。这使得数据中心之间只有一个很低的耦合,但是由于故障检测,连接缓存和复用,跨数据中心的请求都是相对快速和可靠的。Consul 服务注册发现流程Consul在业界最广泛的用途就是作为服务注册中心,同Eureka类型,consul作为服务注册中心,它的注册和发现过程如下图:在上面的流程图上有三个角色,分别为服务注册中心、服务提供者、服务消费者。§ 服务提供者Provider启动的时候,会向Consul发送一个请求,将自己的host、ip、应用名、健康检查等元数据信息发送给Consul§ Consul 接收到Provider 的注册后,定期向Provider 发送健康检查的请求,检验Provider是否健康§ 服务消费者Consumer会从注册中心Consul中获取服务注册列表,当服务消费者消费服务时,根据应用名从服务注册列表获取到具体服务的实例(1个或者多个),从而完成服务的调用。Consul VS EurekaEureka是一种服务发现工具。该体系结构主要是客户端/服务器,每个数据中心有一组Eureka服务器,通常每个可用区域一个。通常,Eureka的客户使用嵌入式SDK来注册和发现服务。对于非本地集成的客户端,使用Ribbon等边车通过Eureka透明地发现服务。Eureka使用尽力而为的复制提供弱一致的服务视图。当客户端向服务器注册时,该服务器将尝试复制到其他服务器但不提供保证。服务注册的生存时间很短(TTL),要求客户端对服务器进行心跳检测。不健康的服务或节点将停止心跳,导致它们超时并从注册表中删除。发现请求可以路由到任何服务,由于尽力复制,这些服务可以提供过时或丢失的数据。这种简化的模型允许轻松的集群管理和高可扩展性。Consul提供了一系列超级功能,包括更丰富的运行状况检查,键/值存储和多数据中心感知。Consul需要每个数据中心中的一组服务器,以及每个客户端上的代理,类似于使用像Ribbon这样的边车。Consul代理允许大多数应用程序不知道Consul,通过配置文件执行服务注册以及通过DNS或负载平衡器sidecars进行发现。Consul提供强大的一致性保证,因为服务器使用Raft协议复制状态。Consul支持丰富的运行状况检查,包括TCP,HTTP,Nagios / Sensu兼容脚本或基于的Eureka的TTL。客户端节点参与基于gossip的健康检查,该检查分发健康检查的工作,而不像集中式心跳,这成为可扩展性挑战。发现请求被路由到当选的Consul领导者,这使他们默认情况下非常一致。允许过时读取的客户端允许任何服务器处理其请求,从而允许像Eureka一样的线性可伸缩性。Consul的强烈一致性意味着它可以用作领导者选举和集群协调的锁定服务。Eureka不提供类似的保证,并且通常需要为需要执行协调或具有更强一致性需求的服务运行ZooKeeper。Consul提供了支持面向服务的体系结构所需的功能工具包。这包括服务发现,还包括丰富的运行状况检查,锁定,键/值,多数据中心联合,事件系统和ACL。Consul和consul-template和envconsul等工具生态系统都试图最大限度地减少集成所需的应用程序更改,以避免需要通过SDK进行本机集成。Eureka是更大的Netflix OSS套件的一部分,该套件期望应用程序相对同质且紧密集成。因此,Eureka只解决了有限的一部分问题,期望其他工具如ZooKeeper可以同时使用。Eureka Server端采用的是P2P的复制模式,但是它不保证复制操作一定能成功,因此它提供的是一个最终一致性的服务实例视图;Client端在Server端的注册信息有一个带期限的租约,一旦Server端在指定期间没有收到Client端发送的心跳,则Server端会认定为Client端注册的服务是不健康的,定时任务将会将其从注册表中删除。Consul与Eureka不同,Consul采用Raft算法,可以提供强一致性的保证,Consul的agent相当于Netflix Ribbon + Netflix Eureka Client,而且对应用来说相对透明,同时相对于Eureka这种集中式的心跳检测机制,Consul的agent可以参与到基于goosip协议的健康检查,分散了server端的心跳检测压力。除此之外,Consul为多数据中心提供了开箱即用的原生支持等。Consul下载和安装Consul采用Go语言编写,支持Linux、Mac、Windows等各大操作系统,本文使用windows操作系统,下载地址:https://www.consul.io/downloads.html,下完成后解压到计算机目录下,解压成功后,只有一个可执行的consul.exe可执行文件。打开cmd终端,切换到目录,执行以下命令:1.  consul --version终端显示如下:1.  Consulv1.4.22.  Protocol2spoken bydefault, understands 2to 3(agent will automatically usep3.  rotocol >2whenspeaking to compatible agents)证明consul下载成功了,并可执行。consul的一些常见的执行命令如下:命令解释示例agent运行一个consul agentconsul agent -devjoin将agent加入到consul集群consul join IPmembers列出consul cluster集群中的membersconsul membersleave将节点移除所在集群consul leave更多命令请查看官方网站:https://www.consul.io/docs/commands/index.html开发模式启动:1.  consul agent -dev 启动成功,在浏览器**问:http://localhost:8500,显示的界面如下:spring cloud consul该项目通过自动配置并绑定到Spring环境和其他Spring编程模型成语,为Spring Boot应用程序提供Consul集成。通过几个简单的注释,您可以快速启用和配置应用程序中的常见模式,并使用基于Consul的组件构建大型分布式系统。提供的模式包括服务发现,控制总线和配置。智能路由(Zuul)和客户端负载平衡(Ribbon),断路器(Hystrix)通过与Spring Cloud Netflix的集成提供。使用spring cloud consul来服务注册与发现本小节以案例的形式来讲解如何使用Spring Cloud Consul来进行服务注册和发现的,并且使用Feign来消费服务。再讲解之前,已经启动consul的agent,并且在浏览器上http://localhost:8500能够显示正确的页面。本案例一共有2个工程,分别如下:工程名端口描述consul-provider8763服务提供者consul-consumer8765服务消费者其中,服务提供者和服务消费者分别向consul注册,注册完成后,服务消费者通过FeignClient来消费服务提供者的服务。服务提供者consul-provider创建一个工程consul-provider,在工程的pom文件引入以下依赖,包括consul-discovery的起步依赖,该依赖是spring cloud consul用来向consul 注册和发现服务的依赖,采用REST API的方式进行通讯。另外加上web的起步依赖,用于对外提供REST API。代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-consul-discovery</artifactId>4.  </dependency>5.  <dependency>6.      <groupId>org.springframework.boot</groupId>7.      <artifactId>spring-boot-starter-web</artifactId>8.  </dependency>在工程的配置文件application.yml做下以下配置:1.  server:2.    port: 87633.  spring:4.    application:5.      name: consul-provider6.    cloud:7.      consul:8.        host: localhost9.        port: 850010.        discovery:11.          serviceName: consul-provider上面的配置,指定了程序的启动端口为8763,应用名为consul-provider,consul注册中心的地址为localhost:8500在程序员的启动类ConsulProviderApplication加上@EnableDiscoveryClient注解,开启服务发现的功能。1.  @SpringBootApplication2.  @EnableDiscoveryClient3.  publicclassConsulProviderApplication{4.    5.      publicstaticvoidmain(String[] args) {6.          SpringApplication.run(ConsulProviderApplication.class, args);7.      }8.    9.  }写一个RESTAPI,该API为一个GET请求,返回当前程序的启动端口,代码如下。1.  @RestController2.  publicclassHiController{3.    4.      @Value("${server.port}")5.      Stringport;6.      @GetMapping("/hi")7.      publicStringhome(@RequestParamStringname) {8.          return"hi "+name+",i am from port:"+port;9.      }10.   11.  }启动工程,在浏览器**问http://localhost:8500,页面显示如下:从上图可知,consul-provider服务已经成功注册到consul上面去了。服务消费者consul-provider服务消费者的搭建过程同服务提供者,在pom文件中引入的依赖同服务提供者,在配置文件application.yml配置同服务提供者,不同的点在端口为8765,服务名为consul-consumer。写一个FeignClient,该FeignClient调用consul-provider的REST API,代码如下:1.  @FeignClient(value = "consul-provider")2.  publicinterfaceEurekaClientFeign{3.    4.    5.      @GetMapping(value = "/hi")6.      StringsayHiFromClientEureka(@RequestParam(value = "name") Stringname);7.  }Service层代码如下:1.  @Service2.  publicclassHiService{3.    4.      @Autowired5.      EurekaClientFeigneurekaClientFeign;6.    7.    8.      publicStringsayHi(Stringname){9.          return eurekaClientFeign.sayHiFromClientEureka(name);10.      }11.  }对外提供一个REST API,该API调用了consul-provider的服务,代码如下:1.  @RestController2.  publicclassHiController{3.      @Autowired4.      HiServicehiService;5.    6.      @GetMapping("/hi")7.      publicStringsayHi(@RequestParam( defaultValue = "forezp",required = false)Stringname){8.          returnhiService.sayHi(name);9.      }10.  }在浏览器**问http://localhost:8765/hi,浏览器响应如下:hi forezp,i am from port:8763这说明consul-consumer已经成功调用了consul-provider的服务。这说明consul-provider的服务已经注册到了consul的注册中心上面去了。consul-consumer能够获取注册中心的注册列表来获来消费服务。使用Spring Cloud Consul Config来做服务配置中心Consul不仅能用来服务注册和发现,Consul而且支持Key/Value键值对的存储,可以用来做配置中心。Spring Cloud 提供了Spring Cloud Consul Config依赖去和Consul相集成,用来做配置中心。现在以案例的形式来讲解如何使用Consul作为配置中心,本案例在上一个案例的consul-provider基础上进行改造。首先在工程的pom文件加上consul-config的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-consul-config</artifactId>4.  </dependency>然后在配置文件application.yml加上以下的以下的配置,配置如下:1.  spring:2.    profiles:3.      active: dev 上面的配置指定了SpringBoot启动时的读取的profiles为dev。然后再工程的启动配置文件bootstrap.yml文件中配置以下的配置:1.  spring:2.    application:3.      name: consul-provider4.    cloud:5.      consul:6.        host: localhost7.        port: 85008.        discovery:9.          serviceName: consul-provider10.        config:11.          enabled: true12.          format: yaml           13.          prefix: config     14.          profile-separator: ':'    15.          data-key: data           关于spring.cloud.consul.config的配置项描述如下:§ enabled 设置config是否启用,默认为true§ format 设置配置的值的格式,可以yaml和properties§ prefix 设置配的基本目录,比如config§ defaultContext 设置默认的配置,被所有的应用读取,本例子没用的§ profileSeparator profiles配置分隔符,默认为‘,’§ date-key为应用配置的key名字,值为整个应用配置的字符串。网页**问consul的KV存储的管理界面,即http://localhost:8500/ui/dc1/kv,创建一条记录,key值为:config/consul-provider:dev/data value值如下:1.  foo:2.    bar: bar13.  server:4.    port: 8081在consul-provider工程新建一个API,该API返回从consul 配置中心读取foo.bar的值,代码如下:1.  @RestController2.  publicclassFooBarController{3.    4.      @Value("${foo.bar}")5.      StringfooBar;6.    7.      @GetMapping("/foo")8.      publicStringgetFooBar() {9.          returnfooBar;10.      }11.  }启动工程,可以看到程序的启动端口为8081,即是consul的配置中心配置的server.port端口。工程启动完成后,在浏览器**问http://localhost:8081/foo,页面显示bar1。由此可知,应用consul-provider已经成功从consul的配置中心读取了配置foo.bar的配置。动态刷新配置当使用spring cloud config作为配置中心的时候,可以使用spring cloud config bus支持动态刷新配置。Spring Cloud Comsul Config默认就支持动态刷新,只需要在需要动态刷新的类上加上@RefreshScope注解即可,修改代码如下:1.  @RestController2.  @RefreshScope3.  publicclassFooBarController{4.    5.      @Value("${foo.bar}")6.      StringfooBar;7.    8.      @GetMapping("/foo")9.      publicStringgetFooBar() {10.          returnfooBar;11.      }12.  }启动consul-provider工程,在浏览器**问http://localhost:8081/foo,页面显示bar1。然后在网页**问consul的KV存储的管理界面,即http://localhost:8500/ui/dc1/kv,修改config/consul-provider:dev/data的值,修改后的值如下:1.  foo:2.    bar: bar23.  server: 4.    port: 8081此时不重新启动consul-provider,在浏览器**问http://localhost:8081/foo,页面显示bar2。可见foo.bar的最新配置在应用不重启的情况下已经生效。注意事项§ consul支持的KV存储的Value值不能超过512KB§ Consul的dev模式,所有数据都存储在内存中,重启Consul的时候会导致所有数据丢失,在正式的环境中,Consul的数据会持久化,数据不会丢失。参考资料https://www.consul.io/intro/index.htmlhttps://www.consul.io/docs/internals/architecture.htmlhttps://www.consul.io/intro/vs/eureka.htmlhttp://www.ityouknow.com/springcloud/2018/07/20/spring-cloud-consul.htmlhttps://springcloud.cc/spring-cloud-consul.htmlhttps://www.cnblogs.com/lsf90/p/6021465.htmlhttps://blog.csdn.net/longgeqiaojie304/article/details/85227936 原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud  
  • [技术干货] 方志朋-SpringCloud系列:spring cloud config将配置存储在数据库中
    原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud Spring Cloud Config Server最常见是将配置文件放在本地或者远程Git仓库,放在本地是将将所有的配置文件统一写在Config Server工程目录下,如果需要修改配置,需要重启config server;放在Git仓库,是将配置统一放在Git仓库,可以利用Git仓库的版本控制。本文将介绍使用另外一种方式存放配置信息,即将配置存放在Mysql中。整个流程:Config Sever暴露Http API接口,Config Client 通过调用Config Sever的Http API接口来读取配置Config Server的配置信息,Config Server从数据中读取具体的应用的配置。流程图如下:案例实战在本案例中需要由2个工程,分为config-server和config-client,其中config-server工程需要连接Mysql数据库,读取配置;config-client则在启动的时候从config-server工程读取。本案例Spring Cloud版本为Greenwich.RELEASE,Spring Boot版本为2.1.0.RELEASE。工程描述config-server端口8769,从数据库中读取配置config-client端口8083,从config-server读取配置搭建config-server工程创建工程config-server,在工程的pom文件引入config-server的起步依赖,mysql的连接器,jdbc的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-config-server</artifactId>4.  </dependency>5.  <dependency>6.      <groupId>mysql</groupId>7.      <artifactId>mysql-connector-java</artifactId>8.  </dependency>9.  <dependency>10.      <groupId>org.springframework.boot</groupId>11.      <artifactId>spring-boot-starter-jdbc</artifactId>12.  </dependency>在工程的配置文件application.yml下做以下的配置:1.  spring:2.    profiles:3.       active: jdbc4.    application:5.       name: config-jdbc-server6.    datasource:7.       url: jdbc:mysql://127.0.0.1:3306/config-jdbc?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&serverTimezone=GMT%2B88.       username: root9.       password: 12345610.       driver-class-name: com.mysql.jdbc.Driver11.    cloud:12.       config:13.         label: master14.         server:15.           jdbc: true16.  server:17.    port: 876918.  spring.cloud.config.server.jdbc.sql: SELECT key1, value1 fromconfig_properties whereAPPLICATION=? andPROFILE=? andLABEL=?其中,spring.profiles.active为spring读取的配置文件名,从数据库中读取,必须为jdbc。spring.datasource配置了数据库相关的信息,spring.cloud.config.label读取的配置的分支,这个需要在数据库中数据对应。spring.cloud.config.server.jdbc.sql为查询数据库的sql语句,该语句的字段必须与数据库的表字段一致。在程序的启动文件ConfigServerApplication加上@EnableConfigServer注解,开启ConfigServer的功能,代码如下:1.  @SpringBootApplication2.  @EnableConfigServer3.  publicclassConfigServerApplication{4.    5.      publicstaticvoidmain(String[] args) {6.          SpringApplication.run(ConfigServerApplication.class, args);7.      }8.  }初始化数据库由于Config-server需要从数据库中读取,所以读者需要先安装MySQL数据库,安装成功后,创建config-jdbc数据库,数据库编码为utf-8,然后在config-jdbc数据库下,执行以下的数据库脚本:1.  CREATE TABLE `config_properties`(2.    `id`bigint(20) NOT NULL AUTO_INCREMENT,3.    `key1`varchar(50) COLLATE utf8_bin NOT NULL,4.    `value1`varchar(500) COLLATE utf8_bin DEFAULT NULL,5.    `application`varchar(50) COLLATE utf8_bin NOT NULL,6.    `profile`varchar(50) COLLATE utf8_bin NOT NULL,7.    `label`varchar(50) COLLATE utf8_bin DEFAULT NULL,8.    PRIMARY KEY (`id`)9.  ) ENGINE=InnoDBAUTO_INCREMENT=3DEFAULT CHARSET=utf8 COLLATE=utf8_bin其中key1字段为配置的key,value1字段为配置的值,application字段对应于应用名,profile对应于环境,label对应于读取的分支,一般为master。**数据config-client 的2条数据,包括server.port和foo两个配置,具体数据库脚本如下:1.  insert into`config_properties`(`id`, `key1`, `value1`, `application`, `profile`, `label`) values('1','server.port','8083','config-client','dev','master');2.  insert into`config_properties`(`id`, `key1`, `value1`, `application`, `profile`, `label`) values('2','foo','bar-jdbc','config-client','dev','master');搭建config-client在config-client工程的pom文件,引入web和config的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.boot</groupId>3.      <artifactId>spring-boot-starter-web</artifactId>4.  </dependency>5.    6.  <dependency>7.      <groupId>org.springframework.cloud</groupId>8.      <artifactId>spring-cloud-starter-config</artifactId>9.  </dependency>在程序的启动配置文件bootstrap.yml做程序的相关配置,一定要是bootstrap.yml,不可以是application.yml,bootstrap.yml的读取优先级更高,配置如下:1.  spring:2.    application:3.      name: config-client4.    cloud:5.      config:6.        uri: http://localhost:87697.        fail-fast: true8.    profiles:9.      active: dev其中spring.cloud.config.uri配置的config-server的地址,spring.cloud.config.fail-fast配置的是读取配置失败后,执行快速失败。spring.profiles.active配置的是spring读取配置文件的环境。在程序的启动文件ConfigClientApplication,写一个RestAPI,读取配置文件的foo配置,返回给浏览器,代码如下:1.  @SpringBootApplication2.  @RestController3.  publicclassConfigClientApplication{4.    5.      publicstaticvoidmain(String[] args) {6.          SpringApplication.run(ConfigClientApplication.class, args);7.      }8.    9.      @Value("${foo}")10.      Stringfoo;11.      @RequestMapping(value = "/foo")12.      publicStringhi(){13.          returnfoo;14.      }15.  }依次启动2个工程,其中config-client的启动端口为8083,这个是在数据库中的,可见config-client从config-server中读取了配置。在浏览器**问http://localhost:8083/foo,浏览器显示bar-jdbc,这个是在数据库中的,可见config-client从config-server中读取了配置。参考资料https://cloud.spring.io/spring-cloud-config/single/spring-cloud-config.html#jdbcbackend源码下载https://github.com/forezp/SpringCloudLearning/tree/master/chapter10-5-jdbc 原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud
  • [技术干货] 方志朋-SpringCloud系列:Spring Cloud Alibaba教程:使用Nacos作为服务注册中心
    什么是Nacos?Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。是Spring Cloud A 中的服务注册发现组件,类似于Consul、Eureka,同时它又提供了分布式配置中心的功能,这点和Consul的config类似,支持热加载。Nacos 的关键特性包括:§ 服务发现和服务健康监测§ 动态配置服务,带管理界面,支持丰富的配置维度。§ 动态DNS 服务§ 服务及其元数据管理Nacos下载Nacos依赖于Java环境,所以必须安装Java环境。然后从官网下载Nacos的解压包,安装稳定版的,下载地址:https://github.com/alibaba/nacos/releases本次案例下载的版本为1.0.0 ,下载完成后,解压,在解压后的文件的/bin目录下,windows系统点击startup.cmd就可以启动nacos。linux或mac执行以下命令启动nacos。1.  sh startup.sh -m standalone启动时会在控制台,打印相关的日志。nacos的启动端口为8848,在启动时要保证端口不被占用。珠穆拉马峰的高度是8844,nacos的端口是8848,有点巧合。启动成功,在浏览器**问:http://localhost:8848/nacos,会跳转到登陆界面,默认的登陆用户名为nacos,密码也为nacos。登陆成功后,展示的界面如下:从界面可知,此时没有服务注册到Nacos上。使用Nacos服务注册和发现服务注册和发现是微服务治理的根基,服务注册和发现组件是整个微服务系统的灵魂,选择合适的服务注册和发现组件至关重要,目前主流的服务注册和发现组件有Consul、Eureka、Etcd等。随着Eureka的闭源,Spring cloud netflix-oss组件大规模的进入到了维护期,不再提供新功能,spring cloud alibaba受到开源社区的大力拥护。服务注册在本案例中,使用2个服务注册到Nacos上,分别为nacos-provider和nacos-consumer。构建服务提供者nacos-provider新建一个Spring Boot项目,Spring boot版本为2.1.4.RELEASE,Spring Cloud 版本为Greenwich.RELEASE,在pom文件引入nacos的Spring Cloud起步依赖,代码如下:1.  <dependency>2.              <groupId>org.springframework.cloud</groupId>3.              <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>4.              <version>0.9.0.RELEASE</version>5.  </dependency>在工程的配置文件application.yml做相关的配置,配置如下:1.  server:2.    port:87623.  spring:4.    application:5.      name:nacos-provider6.    cloud:7.      nacos:8.        discovery:9.          server-addr:127.0.0.1:8848在上述的配置的中,程序的启动端口为8762,应用名为nacos-provider,向nacos server注册的地址为127.0.0.1:8848。然后在Spring Boot的启动文件NacosProviderApplication加上@EnableDiscoveryClient注解,代码如下:1.  @SpringBootApplication2.  @EnableDiscoveryClient3.  publicclassNacosProviderApplication{4.    5.      publicstaticvoidmain(String[]args){6.          SpringApplication.run(NacosProviderApplication.class,args);7.      }8.    9.  }构建服务消费者nacos-consuer和nacos-provider一样,构建服务消费者nacos-consumer,nacos-cosumer的启动端口8763。构建过程同nacos-provider,这里省略。验证服务注册个发现分别启动2个工程,待工程启动成功之后,在访问localhost:8848,可以发现nacos-provider和nacos-consumer,均已经向nacos-server注册,如下图所示:服务调用nacos作为服务注册和发现组件时,在进行服务消费,可以选择RestTemplate和Feign等方式。这和使用Eureka和Consul作为服务注册和发现的组件是一样的,没有什么区别。这是因为spring-cloud-starter-alibaba-nacos-discovery依赖实现了Spring Cloud服务注册和发现的相关接口,可以和其他服务注册发现组件无缝切换。提供服务在nacos-provider工程,写一个Controller提供API服务,代码如下:1.  @RestController2.  publicclassProviderController{3.    4.  Loggerlogger=LoggerFactory.getLogger(ProviderController.class);5.    6.  @GetMapping("/hi")7.  publicStringhi(@RequestParam(value ="name",defaultValue ="forezp",required =false)Stringname){8.    9.          return"hi "+name;10.      }11.  }消费服务在这里使用2种方式消费服务,一种是RestTemplate,一种是Feign。使用RestTemplate消费服务RestTemplate可以使用Ribbon作为负载均衡组件,在nacos-consumer工程中引入ribbon的依赖:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-ribbon</artifactId>4.  </dependency>在NacosConsumerApplication启动文件注入RestTemplate的Bean,代码如下:1.      @LoadBalanced2.      @Bean3.      publicRestTemplaterestTemplate(){4.          returnnewRestTemplate();5.      }加上@LoadBalanced注解即可在RestTemplate上开启LoadBalanced负载均衡的功能。写一个消费服务的ConsumerController,代码如下:1.  @RestController2.  publicclassConsumerController{3.    4.      @Autowired5.      RestTemplaterestTemplate;6.    7.   @GetMapping("/hi-resttemplate")8.      publicStringhiResttemplate(){9.          returnrestTemplate.getForObject("http://nacos-provider/hi?name=resttemplate",String.class);10.   11.      }重启工程,在浏览器**问http://localhost:8763/hi-resttemplate,可以在浏览器上展示正确的响应,这时nacos-consumer调用nacos-provider服务成功。是FeignClient调用服务在nacos-consumer的pom文件引入以下的依赖:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.     <artifactId>spring-cloud-starter-openfeign</artifactId>4.  </dependency>在NacosConsumerApplication启动文件上加上@EnableFeignClients注解开启FeignClient的功能。1.  @EnableFeignClients2.  publicclassNacosConsumerApplication{3.    4.      publicstaticvoidmain(String[]args){5.          SpringApplication.run(NacosConsumerApplication.class,args);6.      }写一个FeignClient,调用nacos-provider的服务,代码如下:1.  @FeignClient("nacos-provider")2.  publicinterfaceProviderClient{3.    4.      @GetMapping("/hi")5.      Stringhi(@RequestParam(value ="name",defaultValue ="forezp",required =false)Stringname);6.  }写一个消费API,该API使用ProviderClient来调用nacos-provider的API服务,代码如下:1.  @RestController2.  publicclassConsumerController{3.    4.    5.      @Autowired6.      ProviderClientproviderClient;7.    8.      @GetMapping("/hi-feign")9.      publicStringhiFeign(){10.         returnproviderClient.hi("feign");11.      }12.  }重启工程,在浏览器**问http://localhost:8763/hi-feign,可以在浏览器上展示正确的响应,这时nacos-consumer调用nacos-provider服务成功。总结本文比较详细的介绍了如何使用Nacos作为服务注册中心,并使用案例介绍了如何在使用nacos作为服务注册中心时消费服务。下一篇教程将介绍如何使用nacos作为分布式配置中心。源码下载https://github.com/forezp/SpringCloudLearning/tree/master/springcloud-alibaba/nacos-discovery参考资料https://nacos.io/zh-cn/docs/what-is-nacos.html 原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架Spring Cloud 
  • [技术干货] 方志朋SpringCloud系列—Spring Cloud Alibba教程:如何使用Nacos作为配置中心
    在上一篇文章中讲解了如何使用Nacos作为服务注册中心注册。Nacos除了可以作为服务注册中心,它还有服务配置中心的功能。类似于consul config,Nacos 是支持热加载的。本篇文章将讲述如何使用Nacos作为配置中心。本案例是在上一篇文章(Nacos作为服务注册与发现)的nacos-provider工程上改造的,在工程的pom文件引入nacos-config的Spring cloud依赖,版本为0.9.0. RELEASE,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-alibaba-nacos-config</artifactId>4.      <version>0.9.0.RELEASE</version>5.  </dependency>在bootstrap.yml(一定是bootstrap.yml文件,不是application.yml文件)文件配置以下内容:1.  spring:2.    application:3.      name: nacos-provider4.    cloud:5.      nacos:6.        config:7.          server-addr: 127.0.0.1:88488.          file-extension: yaml9.          prefix: nacos-provider10.   profiles:11.     active: dev在上面的配置中,配置了nacos config server的地址,配置的扩展名是ymal(目前仅支持ymal和properties)。注意是没有配置server.port的,sever.port的属性在nacos中配置。上面的配置是和Nacos中的 dataId 的格式是对应的,nacos的完整格式如下:1.  ${prefix}-${spring.profile.active}.${file-extension}§  prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。§  spring.profile.active 即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profile.active 为空时,对应的连接符- 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}§  file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。启动nacos,登陆localhost:8848/nacos,创建一个data id ,完整的配置如图所示:写一个RestController,在Controller上添加 @RefreshScope 实现配置的热加载。代码如下:1.  @RestController2.  @RefreshScope3.  public class ConfigController {4.   5.      @Value("${username:lily}")6.      private String username;7.   8.      @RequestMapping("/username")9.      public String get() {10.         return username;11.     }12. }启动工程nacos-provider,在浏览器**问localhost:8761/username,可以返回在nacos控制台上配置的username。在nacos 网页上更改username的配置,在不重启nacos-provider工程的情况下,重新访问localhost:8761/username,返回的事修改后的值,可见nacos作为配置中心实现了热加载功能。原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架Spring Cloud