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做爲配置中心實現了熱加載功能

相關文章
相關標籤/搜索