后期更新内容移步到我的网站:www.upheart.tophtml
Spring Cloud版本为Finchley.RELEASEjava
建立服务注册中心node
引入spring-cloud-starter-netflix-eureka-server的依赖linux
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
复制代码
启动一个服务注册中心,只须要一个注解@EnableEurekaServer,这个注解须要在springboot工程的启动application类上加:git
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run( EurekaServerApplication.class, args );
}
}
复制代码
eureka是一个高可用的组件,它没有后端缓存,每个实例注册以后须要向注册中心发送心跳(所以能够在内存中完成),在默认状况下erureka server也是一个eureka client ,必需要指定一个 server。eureka server的配置文件appication.yml:github
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
application:
name: eurka-server
复制代码
经过eureka.client.registerWithEureka:false和fetchRegistry:false来代表本身是一个eureka serverweb
eureka server 是有界面的,启动工程,打开浏览器访问:http://localhost:8761spring
建立一个服务提供者 (eureka client)sql
当client向server注册时,它会提供一些元数据,例如主机和端口,URL,主页等。Eureka server 从每一个client实例接收心跳消息。 若是心跳超时,则一般将该实例从注册server中删除json
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
复制代码
经过注解@EnableEurekaClient 代表本身是一个eurekaclient
@SpringBootApplication
@EnableEurekaClient
@RestController
public class ServiceHiApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceHiApplication.class, args );
}
@Value("${server.port}")
String port;
@RequestMapping("/hi")
public String home(@RequestParam(value = "name", defaultValue = "forezp") String name) {
return "hi " + name + " ,i am from port:" + port;
}
}
复制代码
仅仅@EnableEurekaClient是不够的,还须要在配置文件中注明本身的服务注册中心的地址,application.yml配置文件以下:
server:
port: 8762
spring:
application:
name: service-hi
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
复制代码
须要指明spring.application.name,这个很重要,这在之后的服务与服务之间相互调用通常都是根据这个name 启动工程,打开http://localhost:8761 ,即eureka server 的网址
你会发现一个服务已经注册在服务中了,服务名为SERVICE-HI ,端口为8762
这时打开 http://localhost:8762/hi?name=forezp
Spring cloud有两种服务调用方式,一种是ribbon+restTemplate,另外一种是feign
ribbon是一个负载均衡客户端,能够很好的控制htt和tcp的一些行为。Feign默认集成了ribbon
在工程的启动类中,经过@EnableDiscoveryClient向服务中心注册;而且向程序的ioc注入一个bean: restTemplate;并经过@LoadBalanced注解代表这个restRemplate开启负载均衡的功能
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceRibbonApplication.class, args );
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
复制代码
写一个测试类HelloService,经过以前注入ioc容器的restTemplate来消费service-hi服务的“/hi”接口,在这里咱们直接用的程序名替代了具体的url地址,在ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名,代码以下:
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
public String hiService(String name) {
return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
}
}
复制代码
写一个controller,在controller中用调用HelloService 的方法,代码以下:
@RestController
public class HelloControler {
@Autowired
HelloService helloService;
@GetMapping(value = "/hi")
public String hi(@RequestParam String name) {
return helloService.hiService( name );
}
}
复制代码
在浏览器上屡次访问http://localhost:8764/hi?name=forezp
说明当咱们经过调用restTemplate.getForObject(“http://SERVICE-HI/hi?name=”+name,String.class)方法时,已经作了负载均衡,访问了不一样的端口的服务实例
Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只须要建立一个接口并注解。它具备可插拔的注解特性,可以使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果
简而言之:
Feign 采用的是基于接口的注解
Feign 整合了ribbon,具备负载均衡的能力
整合了Hystrix,具备熔断的能力
复制代码
引入Feign的起步依赖spring-cloud-starter-feign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
复制代码
在程序的启动类ServiceFeignApplication ,加上@EnableFeignClients注解开启Feign的功能:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceFeignApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceFeignApplication.class, args );
}
}
复制代码
定义一个feign接口,经过@ FeignClient(“服务名”),来指定调用哪一个服务。好比在代码中调用了service-hi服务的“/hi”接口,代码以下:
@FeignClient(value = "service-hi")
public interface SchedualServiceHi {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String sayHiFromClientOne(@RequestParam(value = "name") String name);
}
复制代码
在Web层的controller层,对外暴露一个"/hi"的API接口,经过上面定义的Feign客户端SchedualServiceHi 来消费服务。代码以下:
@RestController
public class HiController {
//编译器报错,无视。 由于这个Bean是在程序启动的时候注入的,编译器感知不到,因此报错。
@Autowired
SchedualServiceHi schedualServiceHi;
@GetMapping(value = "/hi")
public String sayHi(@RequestParam String name) {
return schedualServiceHi.sayHiFromClientOne( name );
}
}
复制代码
启动程序,屡次访问http://localhost:8765/hi?name=forezp
在Spring Cloud能够用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务一般会集群部署。因为网络缘由或者自身的缘由,服务并不能保证100%可用,若是单个服务出现问题,调用这个服务就会出现线程阻塞,此时如有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,致使服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统形成灾难性的严重后果,这就是服务故障的“雪崩”效应
Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合
较底层的服务若是出现故障,会致使连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric 是5秒20次) 断路器将会被打开
断路打开后,可用避免连锁故障,fallback方法能够直接返回一个固定值
加入spring-cloud-starter-netflix-hystrix的起步依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
复制代码
在程序的启动类ServiceRibbonApplication 加@EnableHystrix注解开启Hystrix:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableHystrix
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceRibbonApplication.class, args );
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
复制代码
改造HelloService类,在hiService方法上加上@HystrixCommand注解。该注解对该方法建立了熔断器的功能,并指定了fallbackMethod熔断方法,熔断方法直接返回了一个字符串,字符串为"hi,"+name+",sorry,error!",代码以下:
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String hiService(String name) {
return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
}
public String hiError(String name) {
return "hi,"+name+",sorry,error!";
}
}
复制代码
启动:service-ribbon 工程,当咱们访问http://localhost:8764/hi?name=forezp
此时关闭 service-hi 工程,当咱们再访问http://localhost:8764/hi?name=forezp
当 service-hi 工程不可用的时候,service-ribbon调用 service-hi的API接口时,会执行快速失败,直接返回一组字符串,而不是等待响应超时,这很好的控制了容器的线程阻塞
Feign是自带断路器的,在D版本的Spring Cloud以后,它没有默认打开。须要在配置文件中配置打开它,在配置文件加如下代码:
feign.hystrix.enabled=true
复制代码
基于service-feign工程进行改造,只须要在FeignClient的SchedualServiceHi接口的注解中加上fallback的指定类就好了:
@FeignClient(value = "service-hi",fallback = SchedualServiceHiHystric.class)
public interface SchedualServiceHi {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String sayHiFromClientOne(@RequestParam(value = "name") String name);
}
复制代码
SchedualServiceHiHystric须要实现SchedualServiceHi 接口,并注入到Ioc容器中,代码以下:
@Component
public class SchedualServiceHiHystric implements SchedualServiceHi {
@Override
public String sayHiFromClientOne(String name) {
return "sorry "+name;
}
}
复制代码
启动四servcie-feign工程,浏览器打开http://localhost:8765/hi?name=forezp,注意此时service-hi工程没有启动,网页显示:
sorry forezp
复制代码
打开service-hi工程,再次访问,浏览器显示:
hi forezp,i am from port:8762
复制代码
这证实断路器起到做用了
Hystrix Dashboard是做为断路器状态的一个组件,提供了数据监控和友好的图形化界面
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
复制代码
在程序的入口ServiceHiApplication类,加上@EnableHystrix注解开启断路器,这个是必须的,而且须要在程序中声明断路点HystrixCommand;加上@EnableHystrixDashboard注解,开启HystrixDashboard
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@RestController
@EnableHystrix
@EnableHystrixDashboard
@EnableCircuitBreaker
public class ServiceHiApplication {
/** * 访问地址 http://localhost:8762/actuator/hystrix.stream * @param args */
public static void main(String[] args) {
SpringApplication.run( ServiceHiApplication.class, args );
}
@Value("${server.port}")
String port;
@RequestMapping("/hi")
@HystrixCommand(fallbackMethod = "hiError")
public String home(@RequestParam(value = "name", defaultValue = "forezp") String name) {
return "hi " + name + " ,i am from port:" + port;
}
public String hiError(String name) {
return "hi,"+name+",sorry,error!";
}
}
复制代码
打开http://localhost:8762/actuator/hystrix.stream,能够看到一些具体的数据
打开localhost:8762/hystrix
当咱们有不少个服务的时候,这就须要聚合因此服务的Hystrix Dashboard的数据了
看单个的Hystrix Dashboard的数据并无什么多大的价值,要想看这个系统的Hystrix Dashboard数据就须要用到Hystrix Turbine。Hystrix Turbine将每一个服务Hystrix Dashboard数据进行了整合
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
复制代码
在其入口类ServiceTurbineApplication加上注解@EnableTurbine,开启turbine,@EnableTurbine注解包含了@EnableDiscoveryClient注解,即开启了注册服务
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@RestController
@EnableHystrix
@EnableHystrixDashboard
@EnableCircuitBreaker
@EnableTurbine
public class ServiceTurbineApplication {
/** * http://localhost:8764/turbine.stream */
public static void main(String[] args) {
SpringApplication.run( ServiceTurbineApplication.class, args );
}
}
复制代码
配置文件application.yml:
server:
port: 8764
spring:
application:
name: service-turbine
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
endpoints:
web:
exposure:
include: "*"
cors:
allowed-origins: "*"
allowed-methods: "*"
turbine:
app-config: service-hi,service-lucy
aggregator:
clusterConfig: default
clusterNameExpression: new String("default")
combine-host: true
instanceUrlSuffix:
default: actuator/hystrix.stream
复制代码
打开浏览器输入:http://localhost:8764/turbine.stream
在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先通过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),而后再到具体的服务,服务统一注册到高可用的服务注册中心集群,服务的全部的配置文件由配置服务管理配置服务的配置文件放在git仓库,方便开发人员随时改配置
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,好比/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
复制代码
在其入口applicaton类加上注解@EnableZuulProxy,开启zuul的功能:
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
@EnableDiscoveryClient
public class ServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceZuulApplication.class, args );
}
}
复制代码
加上配置文件application.yml加上如下的配置代码:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8769
spring:
application:
name: service-zuul
zuul:
routes:
api-a:
path: /api-a/**
serviceId: service-ribbon
api-b:
path: /api-b/**
serviceId: service-feign
复制代码
首先指定服务注册中心的地址为http://localhost:8761/eureka/,服务的端口为8769,服务名为service-zuul;以/api-a/ 开头的请求都转发给service-ribbon服务;以/api-b/开头的请求都转发给service-feign服务;
zuul不只只是路由,而且还能过滤,作一些安全验证
@Component
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if(accessToken == null) {
log.warn("token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
}catch (Exception e){}
return null;
}
log.info("ok");
return null;
}
}
复制代码
filterType:返回一个字符串表明过滤器的类型,在zuul中定义了四种不一样生命周期的过滤器类型,具体以下:
pre:路由以前
routing:路由之时
post: 路由以后
error:发送错误调用
复制代码
filterOrder:过滤的顺序 shouldFilter:这里能够写逻辑判断,是否要过滤,true,永远过滤 run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问
Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关做为流量的,在微服务系统中有着很是做用,网关常见的功能有路由转发、权限校验、限流控制等做用
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
复制代码
在spring cloud gateway中使用RouteLocator的Bean进行路由转发,将请求进行处理,最后转发到目标的下游服务。在本案例中,会将请求转发到http://httpbin.org:80这个地址上。代码以下:
@SpringBootApplication
@RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(p -> p
.path("/get")
.filters(f -> f.addRequestHeader("Hello", "World"))
.uri("http://httpbin.org:80"))
.build();
}
}
复制代码
在上面的myRoutes方法中,使用了一个RouteLocatorBuilder的bean去建立路由,除了建立路由RouteLocatorBuilder可让你添加各类predicates和filters,predicates断言的意思,顾名思义就是根据具体的请求的规则,由具体的route去处理,filters是各类过滤器,用来对请求作各类判断和修改
上面建立的route可让请求“/get”请求都转发到“httpbin.org/get”。在route…
启动springboot项目,在浏览器上http://localhost:8080/get,浏览器显示以下:
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Cache-Control": "max-age=0",
"Connection": "close",
"Cookie": "_ga=GA1.1.412536205.1526967566; JSESSIONID.667921df=node01oc1cdl4mcjdx1mku2ef1l440q1.node0; screenResolution=1920x1200",
"Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:60036\"",
"Hello": "World",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"X-Forwarded-Host": "localhost:8080"
},
"origin": "0:0:0:0:0:0:0:1, 210.22.21.66",
"url": "http://localhost:8080/get"
}
复制代码
可见当咱们向gateway工程请求“/get”,gateway会将工程的请求转发到“httpbin.org/get”,而且在转发之…
注意HTTPBin展现了请求的header hello和值world
使用Hystrix 在spring cloud gateway中可使用Hystrix。Hystrix是 spring cloud中一个服务熔断降级的组件,在微服务系统有着十分重要的做用 Hystrix是 spring cloud gateway中是以filter的形式使用的,代码以下:
@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
String httpUri = "http://httpbin.org:80";
return builder.routes()
.route(p -> p
.path("/get")
.filters(f -> f.addRequestHeader("Hello", "World"))
.uri(httpUri))
.route(p -> p
.host("*.hystrix.com")
.filters(f -> f
.hystrix(config -> config
.setName("mycmd")
.setFallbackUri("forward:/fallback")))
.uri(httpUri))
.build();
}
复制代码
在上面的代码中,咱们使用了另一个router,该router使用host去断言请求是否进入该路由,当请求的host有“*.hystrix.com”,都会进入该router,该router中有一个hystrix的filter,该filter能够配置名称、和指向性fallback的逻辑的地址,好比本案例中重定向到了“/fallback”
如今写的一个“/fallback”的l逻辑:
@RequestMapping("/fallback")
public Mono<String> fallback() {
return Mono.just("fallback");
}
复制代码
Mono是一个Reactive stream,对外输出一个“fallback”字符串
使用curl执行如下命令:
curl --dump-header - --header 'Host: www.hystrix.com' http://localhost:8080/delay/3
复制代码
返回的响应为:
fallback
复制代码
可见,带hostwww.hystrix.com的请求执行了hystrix的fallback的逻辑
在分布式系统中,因为服务数量巨多,为了方便服务配置文件统一管理,实时更新,因此须要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
复制代码
在程序的入口Application类加上@EnableConfigServer注解开启配置服务器的功能,代码以下:
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
复制代码
须要在程序的配置文件application.properties文件配置如下:
spring.application.name=config-server
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/forezp/SpringcloudConfig/
spring.cloud.config.server.git.searchPaths=respo
spring.cloud.config.label=master
spring.cloud.config.server.git.username=
spring.cloud.config.server.git.password=
复制代码
spring.cloud.config.server.git.uri:配置git仓库地址
spring.cloud.config.server.git.searchPaths:配置仓库路径
spring.cloud.config.label:配置仓库的分支
spring.cloud.config.server.git.username:访问git仓库的用户名
spring.cloud.config.server.git.password:访问git仓库的用户密码
复制代码
若是Git仓库为公开仓库,能够不填写用户名和密码,若是是私有仓库须要填写
远程仓库https://github.com/forezp/SpringcloudConfig/ 中有个文件config-client-dev.properties文件中有一个属性:
foo = foo version 3
复制代码
启动程序:访问http://localhost:8888/foo/dev
{"name":"foo","profiles":["dev"],"label":"master",
"version":"792ffc77c03f4b138d28e89b576900ac5e01a44b","state":null,"propertySources":[]}
复制代码
证实配置服务中心能够从远程程序获取配置信息
http请求地址和资源文件映射以下:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
复制代码
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
复制代码
其配置文件bootstrap.properties:
spring.application.name=config-client
spring.cloud.config.label=master
spring.cloud.config.profile=dev
spring.cloud.config.uri= http://localhost:8888/
server.port=8881
复制代码
spring.cloud.config.label 指明远程仓库的分支
spring.cloud.config.profile
dev开发环境配置文件
test测试环境
pro正式环境
spring.cloud.config.uri= http://localhost:8888/ 指明配置服务中心的网址
复制代码
程序的入口类,写一个API接口“/hi”,返回从配置中心读取的foo变量的值,代码以下:
@SpringBootApplication
@RestController
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
@Value("${foo}")
String foo;
@RequestMapping(value = "/hi")
public String hi(){
return foo;
}
}
复制代码
打开网址访问:http://localhost:8881/hi,网页显示:
foo version 3
这就说明,config-client从config-server获取了foo的属性,而config-server是从git仓库读取的
Spring Cloud Bus 将分布式的节点用轻量的消息代理链接起来。它能够用于广播配置文件的更改或者服务之间的通信,也能够用于监控
加上起步依赖spring-cloud-starter-bus-amqp
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
复制代码
在配置文件application.properties中加上RabbitMq的配置,包括RabbitMq的地址、端口,用户名、密码。并须要加上spring.cloud.bus的三个配置,具体以下:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.cloud.bus.enabled=true
spring.cloud.bus.trace.enabled=true
management.endpoints.web.exposure.include=bus-refresh
复制代码
ConfigClientApplication启动类代码以下:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@RestController
@RefreshScope
public class ConfigClientApplication {
/** * http://localhost:8881/actuator/bus-refresh */
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
@Value("${foo}")
String foo;
@RequestMapping(value = "/hi")
public String hi(){
return foo;
}
}
复制代码
依次启动eureka-server、confg-cserver,启动两个config-client,端口为:888一、8882
访问http://localhost:8881/hi 或者http://localhost:8882/hi 浏览器显示:
foo version 3
复制代码
这时咱们去代码仓库将foo的值改成“foo version 4”,即改变配置文件foo的值。若是是传统的作法,须要重启服务,才能达到配置文件的更新。此时,咱们只须要发送post请求:http://localhost:8881/actuator/bus-refresh,你会发现config-client会从新读取配置文件
/actuator/bus-refresh接口能够指定服务,即便用"destination"参数,好比 “/actuator/bus-refresh?destination=customers:**” 即刷新服务名为customers的全部服务
当git文件更改的时候,经过pc端用post 向端口为8882的config-client发送请求/bus/refresh/;此时8882端口会发送一个消息,由消息总线向其余服务传递,从而使整个微服务集群都达到更新配置文件
Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案,而且兼容支持了 zipkin,你只须要在pom文件中引入相应的依赖便可
微服务架构上经过业务来划分服务的,经过REST调用,对外暴露的一个接口,可能须要不少个服务协同才能完成这个接口功能,若是链路上任何一个服务出现问题或者网络超时,都会造成致使接口调用失败。随着业务的不断扩张,服务之间互相调用会愈来愈复杂
有三个工程组成:一个server-zipkin,它的主要做用使用ZipkinServer 的功能,收集调用数据,并展现;一个service-hi,对外暴露hi接口;一个service-miya,对外暴露miya接口;这两个service能够相互调用;而且只有调用了,server-zipkin才会收集数据的,这就是为何叫服务追踪了。
构建server-zipkin
在spring Cloud为F版本的时候,已经不须要本身构建Zipkin Server了,只须要下载jar便可,下载地址:
下载完成jar 包以后,须要运行jar,以下:
java -jar zipkin-server-2.10.1-exec.jar
访问浏览器localhost:9411
建立service-hi
在其pom引入起步依赖spring-cloud-starter-zipkin
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
复制代码
在其配置文件application.yml指定zipkin server的地址,经过配置“spring.zipkin.base-url”指定:
server.port=8988
spring.zipkin.base-url=http://localhost:9411
spring.application.name=service-hi
复制代码
经过引入spring-cloud-starter-zipkin依赖和设置spring.zipkin.base-url就能够了
对外暴露接口:
package com.forezp;
import brave.sampler.Sampler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.logging.Level;
import java.util.logging.Logger;
@SpringBootApplication
@RestController
public class ServiceHiApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHiApplication.class, args);
}
private static final Logger LOG = Logger.getLogger(ServiceHiApplication.class.getName());
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@RequestMapping("/hi")
public String callHome(){
LOG.log(Level.INFO, "calling trace service-hi ");
return restTemplate.getForObject("http://localhost:8989/miya", String.class);
}
@RequestMapping("/info")
public String info(){
LOG.log(Level.INFO, "calling trace service-hi ");
return "i'm service-hi";
}
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
}
复制代码
建立service-miya
建立过程痛service-hi,引入相同的依赖,配置下spring.zipkin.base-url
对外暴露接口:
package com.forezp;
import brave.sampler.Sampler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.logging.Level;
import java.util.logging.Logger;
@SpringBootApplication
@RestController
public class ServiceMiyaApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceMiyaApplication.class, args);
}
private static final Logger LOG = Logger.getLogger(ServiceMiyaApplication.class.getName());
@RequestMapping("/hi")
public String home(){
LOG.log(Level.INFO, "hi is being called");
return "hi i'm miya!";
}
@RequestMapping("/miya")
public String info(){
LOG.log(Level.INFO, "info is being called");
return restTemplate.getForObject("http://localhost:8988/info",String.class);
}
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
}
复制代码
依次启动上面的工程,打开浏览器访问:http://localhost:9411/
Spring Cloud 版本为Greenwich.RELEASE
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理
是Spring Cloud中的服务注册发现组件,相似于Consul、Eureka,同时它又提供了分布式配置中心的功能,这点和Consul的config相似,支持热加载
Nacos 的关键特性包括:
服务发现和服务健康监测 动态配置服务,带管理界面,支持丰富的配置维度 动态 DNS 服务 服务及其元数据管理
Nacos下载
Nacos依赖于Java环境,因此必须安装Java环境。而后从官网下载Nacos的解压包,安装稳定版的,下载地址:github.com/alibaba/nac…
本次案例下载的版本为1.0.0 ,下载完成后,解压,在解压后的文件的/bin目录下,windows系统点击startup.cmd就能够启动nacos。linux或mac执行如下命令启动nacos
sh startup.sh -m standalone
启动时会在控制台,打印相关的日志。nacos的启动端口为8848,在启动时要保证端口不被占用。珠穆拉马峰的高度是8844,nacos的端口是8848,有点巧合
启动成功,在浏览器上访问:http://localhost:8848/nacos,会跳转到登录界面,默认的登录用户名为nacos,密码也为nacos
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.9.0.RELEASE</version>
</dependency>
复制代码
在工程的配置文件application.yml作相关的配置,配置以下:
server:
port: 8762
spring:
application:
name: nacos-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
复制代码
在上述的配置的中,程序的启动端口为8762,应用名为nacos-provider,向nacos server注册的地址为127.0.0.1:8848
而后在Spring Boot的启动文件NacosProviderApplication加上@EnableDiscoveryClient注解,代码以下:
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {
public static void main(String[] args) {
SpringApplication.run(NacosProviderApplication.class, args);
}
}
复制代码
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-config</artifactId>
<version>0.9.0.RELEASE</version>
</dependency>
复制代码
在bootstrap.yml(必定是bootstrap.yml文件,不是application.yml文件)文件配置如下内容:
spring:
application:
name: nacos-provider
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
prefix: nacos-provider
profiles:
active: dev
复制代码
在上面的配置中,配置了nacos config server的地址,配置的扩展名是ymal(目前仅支持ymal和properties)。注意是没有配置server.port的,sever.port的属性在nacos中配置。上面的配置是和Nacos中的dataId 的格式是对应的,nacos的完整格式以下:
${prefix}-${spring.profile.active}.${file-extension}
复制代码
prefix 默认为 spring.application.name 的值,也能够经过配置项 spring.cloud.nacos.config.prefix来配置 spring.profile.active 即为当前环境对应的 profile,注意:当 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 实现配置的热加载。代码以下:
@RestController
@RefreshScope
public class ConfigController {
@Value("${username:lily}")
private String username;
@RequestMapping("/username")
public String get() {
return username;
}
}
复制代码
启动工程nacos-provider,在浏览器上访问localhost:8761/username,能够返回在nacos控制台上配置的username。在nacos 网页上更改username的配置,在不重启nacos-provider工程的状况下,从新访问localhost:8761/username,返回的事修改后的值,可见nacos做为配置中心实现了热加载功能