SpringCloud学习笔记

后期更新内容移步到我的网站:www.upheart.tophtml

Finchley版本

Spring Cloud版本为Finchley.RELEASEjava

Eureka

建立服务注册中心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

Ribbon

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

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

Hystrix

在Spring Cloud能够用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务一般会集群部署。因为网络缘由或者自身的缘由,服务并不能保证100%可用,若是单个服务出现问题,调用这个服务就会出现线程阻塞,此时如有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,致使服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统形成灾难性的严重后果,这就是服务故障的“雪崩”效应

Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合

较底层的服务若是出现故障,会致使连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric 是5秒20次) 断路器将会被打开

断路打开后,可用避免连锁故障,fallback方法能够直接返回一个固定值

Ribbon使用断路器

加入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中使用断路器

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

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 Turbine

当咱们有不少个服务的时候,这就须要聚合因此服务的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

Zuul

在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 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 Config

在分布式系统中,因为服务数量巨多,为了方便服务配置文件统一管理,实时更新,因此须要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client

Config Server

<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
复制代码

Config Client

<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 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

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便可,下载地址:

dl.bintray.com/openzipkin/…

下载完成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/

Alibaba版本

Spring Cloud 版本为Greenwich.RELEASE

Nacos

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做为配置中心实现了热加载功能

相关文章
相关标签/搜索