傳統項目分爲三層架構,將業務邏輯層、數據庫訪問層、控制層放入在一個項目中。java
優勢:適合於我的或者小團隊開發,不適合大團隊開發。nginx
根據業務需求進行拆分紅N個子系統,多個子系統相互協做才能完成業務流程子系統之間通信使用RPC遠程通信技術。git
優勢:程序員
1.把模塊拆分,使用接口通訊,下降模塊之間的耦合度。github
2.把項目拆分紅若干個子項目,不一樣的團隊負責不一樣的子項目。web
3.增長功能時只須要再增長一個子項目,調用其它系統的接口就能夠。spring
4.能夠靈活的進行分佈式部署。數據庫
有優勢就有缺點,缺點以下:bootstrap
1.系統之間交互須要使用遠程通訊,接口開發增長工做量。api
2.各個模塊有一些通用的業務邏輯沒法共用。
爲了解決上面分佈式架構的缺點,咱們引入了soa架構,SOA:Service Oriented Architecture面向服務的架構。也就是把工程拆分紅服務層、表現層兩個工程。服務層中包含業務邏輯,只須要對外提供服務便可。表現層只須要處理和頁面的交互,業務邏輯都是調用服務層的服務來實現。
多臺服務器部署相同應用構成一個集羣
做用:經過負載均衡設備共同對外提供服務
RPC 的全稱是 Remote Procedure Call 是一種進程間通訊方式。
它容許程序調用另外一個地址空間(一般是共享網絡的另外一臺機器上)的過程或函數,而不用程序員顯式編碼這個遠程調用的細節。即不管是調用本地接口/服務的仍是遠程的接口/服務,本質上編寫的調用代碼基本相同。
好比兩臺服務器A,B,一個應用部署在A服務器上,想要調用B服務器上應用提供的函數或者方法,因爲不在一個內存空間,不能直接調用,這時候須要經過就能夠應用RPC框架的實現來解決
(1)restful是一種架構設計風格,提供了設計原則和約束條件,而不是架構。而知足這些約束條件和原則的應用程序或設計就是 RESTful架構或服務。
(2)soap象訪問協議是一種數據交換協議規範,
是一種輕量的、簡單的、基於XML的協議的規範。SOAP協議和HTTP協議同樣,都是底層的通訊協議,只是請求包的格式不一樣而已,SOAP包是XML格式的。
soap
基於xml並封裝成了符合http協議,所以,它符合任何路由器、 防火牆或代理服務器的要求。
soap可使用任何語言來完成,只要發送正確的soap請求便可,基於soap的服務能夠在任何平臺無需修改便可正常使用。
(3)RPC就是從一臺機器(客戶端)上經過參數傳遞的方式調用另外一臺機器(服務器)上的一個函數或方法(能夠統稱爲服務)並獲得返回的結果。
RPC 會隱藏底層的通信細節(不須要直接處理Socket通信或Http通信)
RPC 是一個請求響應模型。客戶端發起請求,服務器返回響應(相似於Http的工做方式)
RPC 在使用形式上像調用本地函數(或方法)同樣去調用遠程的函數(或方法)。
幾種比較典型的RPC的實現和調用框架。
(1)RMI實現,利用java.rmi包實現,基於Java遠程方法協議(Java Remote Method Protocol)
和java的原生序列化。
(2)Hessian,是一個輕量級的remoting onhttp工具,使用簡單的方法提供了RMI的功能。 基於HTTP協議,採用二進制編解碼。
(3)thrift是一種可伸縮的跨語言服務的軟件框架。thrift容許你定義一個描述文件,描述數據類型和服務接口。依據該文件,編譯器方便地生成RPC客戶端和服務器通訊代碼。
(4)SpringCloud 爲開發人員提供了快速構建分佈式系統的一些工具,包括配置管理、服務發現、斷路器、路由、微代理、事件總線、全局鎖、決策競選、分佈式會話等等。
(4) Dubbo是阿里巴巴公司開源的一個高性能優秀的服務框架,使得應用可經過高性能的 RPC 實現服務的輸出和輸入功能,能夠和 Spring框架無縫集成。
業務系統分解爲多個組件,讓每一個組件都獨立提供離散,自治,可複用的服務能力
經過服務的組合和編排來實現上層的業務流程
做用:簡化維護,下降總體風險,伸縮靈活
架構設計概念,各服務間隔離(分佈式也是隔離),自治(分佈式依賴總體組合)其它特性(單一職責,邊界,異步通訊,獨立部署)是分佈式概念的跟嚴格執行
SOA到微服務架構的演進過程
做用:各服務可獨立應用,組合服務也可系統應用(巨石應用[monolith]的簡化實現策略-平臺思想)
SOA架構主要針對企業級、採用ESB服務(ESB企業服務總線),很是重,須要序列化和反序列化,採用XML格式傳輸。
微服務架構主要互聯網公司,輕量級、小巧,獨立運行,基於Http+Rest+JSON格式傳輸。
ESB也能夠說是傳統中間件技術與XML、Web服務等技術相互結合的產物。
SpringCloud 爲開發人員提供了快速構建分佈式系統的一些工具,包括配置管理、服務發現、斷路器、路由、負載均衡、微代理、事件總線、全局鎖、決策競選、分佈式會話等等。它運行環境簡單,能夠在開發人員的電腦上跑。另外說明spring cloud是基於Springboot的,因此須要開發中對Springboot有必定的瞭解,若是不瞭解的話能夠看螞蟻課堂SpringBoot課程。
服務提供者:提供服務被人調用
消費者:調用被人服務
在這裏,咱們須要用的的組件上Spring Cloud Netflix的Eureka ,eureka是一個服務註冊和發現模塊。
官方的介紹在這裏Eureka wiki。Eureka是Netflix開源的一個RESTful服務,主要用於服務的註冊發現。Eureka由兩個組件組成:Eureka服務器和Eureka客戶端。Eureka服務器用做服務註冊服務器。Eureka客戶端是一個java客戶端,用來簡化與服務器的交互、做爲輪詢負載均衡器,並提供服務的故障切換支持。Netflix在其生產環境中使用的是另外的客戶端,它提供基於流量、資源利用率以及出錯狀態的加權負載均衡。
在我看來,Eureka的吸引力來源於如下幾點:
開源:你們能夠對實現一探究竟,甚至修改源碼。
可靠:通過Netflix多年的生產環境考驗,使用應該比較靠譜省心
功能齊全:不但提供了完整的註冊發現服務,還有Ribbon等能夠配合使用的服務。
基於Java:對於Java程序員來講,使用起來,內心比較有底。
spring cloud可使用Spring Cloud, 與Eureka進行了很好的集成,使用起來很是方便。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!--eureka server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <!-- spring boot test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RC1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
server: port: 8888 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
package com.hongmoshui.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaApp { public static void main(String[] args) { SpringApplication.run(EurekaApp.class, args); } }
http://localhost:8761 ,界面以下:
No application available 沒有服務被發現 ……^_^
由於沒有註冊服務固然不可能有服務被發現了。
建立一個服務提供者 會員服務工程 (eurekaMember),提供會員查詢服務信息
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RC1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8762 spring: application: name: service-member
package com.hongmoshui.controller; import java.util.ArrayList; import java.util.List; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MemberController { @RequestMapping("/getUserList") public List<String> getUserList() { List<String> listUser = new ArrayList<String>(); listUser.add("zhangsan"); listUser.add("lisi"); listUser.add("hongmoshui"); return listUser; } }
經過註解@EnableEurekaClient 代表本身是一個eurekaclient。
package com.hongmoshui.controller; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class MemberApp { public static void main(String[] args) { SpringApplication.run(MemberApp.class, args); } }
須要指明spring.application.name,這個很重要,這在之後的服務與服務之間相互調用通常都是根據這個name 。
啓動工程,打開127.0.0.1:8761 ,即eureka server 的網址:
你會發現一個服務已經註冊在服務中了,服務名爲SERVICE-HI ,端口爲7862
這時打開 http://127.0.0.1:8762/getUserList ,你會在瀏覽器上看到 :
["zhangsan","lisi","hongmoshui"]
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RC1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8764 spring: application: name: service-order
package com.hongmoshui.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @SuppressWarnings("unchecked") @Service public class OrderService { @Autowired RestTemplate restTemplate; public List<String> getOrderByUserList() { return restTemplate.getForObject("http://service-member/getUserList", List.class); } }
package com.hongmoshui.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.hongmoshui.service.OrderService; @RestController public class OrderController { @Autowired OrderService orderService; @RequestMapping(value = "/getOrderByUserList", method = RequestMethod.GET) public List<String> getOrderByUserList() { return orderService.getOrderByUserList(); } }
package com.hongmoshui; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableEurekaClient @SpringBootApplication public class OrderApp { public static void main(String[] args) { SpringApplication.run(OrderApp.class, args); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }
在工程的啓動類中,經過@EnableDiscoveryClient向服務中心註冊;而且向程序的ioc注入一個bean: restTemplate;並經過@LoadBalanced註解代表這個restRemplate開啓負載均衡的功能。
啓動兩個會員服務工程,端口號分別爲876二、8763,訂單服務 使用負載均衡策略輪訓到會員服務接口。
ribbon是一個負載均衡客戶端 相似nginx反向代理,能夠很好的控制htt和tcp的一些行爲。Feign默認集成了ribbon。
@Value("${server.port}") private String serverPort; @RequestMapping("/getUserList") public List<String> getUserList() { List<String> listUser = new ArrayList<String>(); listUser.add("zhangsan"); listUser.add("lisi"); listUser.add("hongmoshui"); listUser.add("端口號:" + serverPort); return listUser; }
@LoadBalanced註解代表這個restRemplate開啓負載均衡的功能。
Feign是一個聲明式的僞Http客戶端,它使得寫Http客戶端變得更簡單。使用Feign,只須要建立一個接口並註解。它具備可插拔的註解特性,可以使用Feign 註解和JAX-RS註解。Feign支持可插拔的編碼器和解碼器。Feign默認集成了Ribbon,並和Eureka結合,默認實現了負載均衡的效果。
簡而言之:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RC1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8765 spring: application: name: service-order-feign
package com.hongmoshui.service; import java.util.List; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; @FeignClient("service-member") public interface OrderFeignService { @RequestMapping("/getUserList") public List<String> getOrderByUserList(); }
@FeignClient 須要調用服務名稱,@RequestMapping服務請求名稱
package com.hongmoshui.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.hongmoshui.service.OrderFeignService; @RestController public class OrderFeignController { @Autowired OrderFeignService orderFeignService; @RequestMapping("/getOrderByUserList") public List<String> getOrderByUserList() { return orderFeignService.getOrderByUserList(); } }
package com.hongmoshui; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class OrderFeignApp { public static void main(String[] args) { SpringApplication.run(OrderFeignApp.class, args); } }
Zuul的主要功能是路由轉發和過濾器。路由功能是微服務的一部分,好比/api/user轉發到到user服務,/api/shop轉發到到shop服務。zuul默認和Ribbon結合實現了負載均衡的功能, 相似於nginx轉發。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RC1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8769 spring: application: name: service-zuul zuul: routes: api-a: path: /api-member/** service-id: service-member api-b: path: /api-order/** service-id: service-order
發送請求http://127.0.0.1:8769/api-member/getMemberAll
轉發到http://127.0.0.1:8762/getMemberAll
開啓網關 @EnableZuulProxy
package com.hongmoshui.zuul; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; @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; } public boolean shouldFilter() { return true; } 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 (!StringUtils.isEmpty(accessToken)) { return 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; } }
package com.hongmoshui.zuul; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication @EnableZuulProxy public class ZuulApp { public static void main(String[] args) { SpringApplication.run(ZuulApp.class, args); } }
若是請求參數中沒有傳入token參數 直接返回報錯信息
傳入token參數能夠正常訪問請求
在微服務架構中,咱們將業務拆分紅一個個的服務,服務與服務之間能夠相互調用(RPC)。爲了保證其高可用,單個服務又必須集羣部署。因爲網絡緣由或者自身的緣由,服務並不能保證服務的100%可用,若是單個服務出現問題,調用這個服務就會出現網絡延遲,此時如有大量的網絡涌入,會造成任務累計,致使服務癱瘓,甚至致使服務「雪崩」。爲了解決這個問題,就出現斷路器模型。
分佈式系統中常常會出現某個基礎服務不可用形成整個系統不可用的狀況, 這種現象被稱爲服務雪崩效應. 爲了應對服務雪崩, 一種常見的作法是手動服務降級. 而Hystrix的出現,給咱們提供了另外一種選擇.
針對形成服務雪崩的不一樣緣由, 可使用不一樣的應對策略:
流量控制 的具體措施包括:
全部的RPC技術裏面服務降級是一個最爲重要的話題,所謂的降級指的是當服務的提供方不可以使用的時候,程序不會出現異常,而會出現本地的操做調
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>
service類的改造【在getOrderByUserList方法上,增長註解@HystrixCommand(fallbackMethod = "orderError"),並在類中增長orderError方法】:
package com.hongmoshui.service; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; @SuppressWarnings("unchecked") @Service public class OrderService { @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "orderError") public List<String> getOrderByUserList() { int i = 1 / 0; return restTemplate.getForObject("http://service-member/getUserList", List.class); } public List<String> orderError() { List<String> listUser = new ArrayList<String>(); listUser.add("not orderUser list"); return listUser; } }
啓動類的改造【增長註解:@EnableHystrix】:
package com.hongmoshui; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableEurekaClient @SpringBootApplication @EnableHystrix public class OrderApp { public static void main(String[] args) { SpringApplication.run(OrderApp.class, args); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }
注:
@HystrixCommand 做用:服務發生錯誤,回調方法。
@EnableHystrix 啓動斷路器
改造service-order-feign工程
配置文件新增:
feign:
hystrix:
enabled: true
新增一個實現類,實現OrderFeignService接口【其方法的實現,就是接口調用失敗時的回調方法】
package com.hongmoshui.service.impl; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Component; import com.hongmoshui.service.OrderFeignService; @Component public class OrderFeignServiceImpl implements OrderFeignService { public List<String> getOrderByUserList() { List<String> listUser = new ArrayList<String>(); listUser.add("not orderUser list"); return listUser; } }
OrderFeignService接口的@FeignClient註解上,增長回調參數【fallback值就是其實現類】
package com.hongmoshui.service; import java.util.List; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import com.hongmoshui.service.impl.OrderFeignServiceImpl; @FeignClient(value = "service-member", fallback = OrderFeignServiceImpl.class) public interface OrderFeignService { @RequestMapping("/getUserList") public List<String> getOrderByUserList(); }
在分佈式系統中,因爲服務數量巨多,爲了方便服務配置文件統一管理,實時更新,因此須要分佈式配置中心組件。在Spring Cloud中,有分佈式配置中心組件spring cloud config ,它支持配置服務放在配置服務的內存中(即本地),也支持放在遠程Git倉庫中。在spring cloud config 組件中,分兩個角色,一是config server,二是config client。
#配置文件的內容 userName=hongmoshui
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR6</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
spring.application.name=config-server server.port=8889 spring.cloud.config.server.git.uri=https://github.com/hongmoshui/maven-web-ver2.0 spring.cloud.config.server.git.searchPaths=src/main/resources/configurationCenter spring.cloud.config.label=master spring.cloud.config.server.git.username=hongmoshui 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倉庫的用戶密碼
在遠程configurationCenter倉庫中,配置了3個配置文件
config-dev.properties:配置有兩個屬性:name=hongmoshui-dev,nickName=yuelang-dev
config-pro.properties:配置有兩個屬性:name=hongmoshui-pro,nickName=yuelang-pro
config-test.properties:配置有兩個屬性:name=hongmoshui-test,nickName=yuelang-test
在服務端獲取文件配置時,其URL與配置文件的映射關係以下:
上面的url會映射{application}-{profile}.properties
對應的配置文件,{label}
對應git上不一樣的分支,默認爲master。
package com.hongmoshui; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableConfigServer public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RC1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
spring.application.name=config server.port=8881 spring.cloud.config.label=master spring.cloud.config.profile=dev spring.cloud.config.uri= http://localhost:8889/
URL與配置文件的映射關係以下:
上面的url會映射{application}-{profile}.properties
對應的配置文件,{label}
對應git上不一樣的分支,默認爲master。
即:上面的配置,會映射到config-dev.properties文件,而後讀取其中的配置信息,存儲在本服務內存中。
若是遠程倉庫的配置文件信息修改了,要同步到本服務,須要重新啓動服務