簡介
摘自百度百科:
SpringCloud是一系列框架的有序集合。它利用SpringBoot的開發便利性巧妙地簡化了分布式系統基礎設施的開發,如服務發現注冊、配置中心、消息總線、負載均衡、斷路器、數據監控等,都可以用SpringBoot的開發風格做到一鍵啟動和部署。SpringCloud並沒有重復制造輪子,它只是將目前各家公司開發的比較成熟、經得起實際考驗的服務框架組合起來,通過SpringBoot風格進行再封裝屏蔽掉了復雜的配置和實現原理,最終給開發者留出了一套簡單易懂、易部署和易維護的分布式系統開發工具包。
三年前我還在大三的時候,自學了dubbo,如今已忘得一干二凈,現在正流行的springCloud,是時候整理一下了。springCloud是一種微服務的框架,最主要的由幾部分組成:provider服務提供者、consumer服務消費者、eureka注冊中心、ribbon負載均衡、actuator服務監控。基本上就是幾個springBoot引入幾個依賴,因為是springBoot,所以開發基本上和以前一樣,同時也支持spring的其他一些組件。
Provider服務提供者
快速構建一個SpringBoot項目,具體構建方法可以參考 https://www.cnblogs.com/m1996/p/13030161.html ,未見簡單方便測試,項目只引入 spring-boot-starter-web , 配置文件只暴露接口8080。由於是服務提供者,對外提供一個Controller,直接返回string "hello cloud"。
依賴如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
Consumer服務消費者
同樣是一個SpringBoot項目,同樣只引入 spring-boot-starter-web , 配置文件只暴露接口7900。
這里解釋一下RestTemplates這個類,關於這個類,這個老哥 https://blog.csdn.net/u012702547/article/details/77917939 的解釋很清楚了,RestTemplates在SpringCloud中,消費者通過這個類訪問生產者,@bean注解是為了實例化這個類,實例化之后通過@AutoWired注解引入,將其交給Spring進行管理。分別啟動兩個項目,分別訪問localhost:8080/provider/demo和http://localhost:7900/consumer/demo應該都能得到“hello cloud”這個結果,說明consumer成功調用了provider中的方法。
問題:
這樣的編碼方式是將接口(http://localhost:8080/provider/demo)硬編碼在代碼中,但是項目發布之后,ip地址必然是變動的。而且,硬編碼的方式肯定是無法實現負載均衡的,就是說如果同時啟動多個provider服務,這種硬編碼方式是無法根據負載均衡策略去調用服務的。
解決方法:
在Dubbo中使用的ZooKeeper作為服務注冊與發現的容器,在Springcloud中使用的是Eureka作為服務注冊與發現的容器。
Eureka注冊中心
同樣是一個SpringBoot項目,引入 spring-boot-starter-web , 配置文件只暴露接口7900。引入 spring-cloud-starter-netflix-eureka-server 依賴,maven依賴如下:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
沒有版本號是因為有可能會和springBoot的版本沖突,導致項目跑步起來,所以把版本交給dependencyManagement 去處理,他會自動回匹配合適的版本號。具體做法如下:
在maven中引入
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
下面是整個Eureka的pom文件,可以參考。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>provider</artifactId> <version>0.0.1-SNAPSHOT</version> <name>provider</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <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> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
然后在Springboot的啟動類上添加@EnableEurekaServer注解,並在yml文件中加入Eureka的配置信息。參考如下:
server: port: 8761 eureka: client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://localhost:8761/eureka/ serviceUrl: defaultZone: http://localhost:8761/eureka/ instance: lease-renewal-interval-in-seconds: 1 lease-expiration-duration-in-seconds: 2
啟動項目,打開網頁 http://localhost:8761/ 會顯示Eureka的實例信息:
這個時候還沒有服務提供者和服務消費者的信息,因為我們的服務還沒有注冊到Eureka。
注冊服務到Eureka
在之前創建的 provider和consumer項目中,引入 spring-cloud-starter-netflix-eureka-client 依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>RELEASE</version>
</dependency>
然后再啟動類上加上注解 @EnableEurekaClient
@SpringBootApplication @EnableEurekaClient public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
最后在yml文件或properties中加入Eureka的配置就可以了。第二個注解就是該實例的名字,會顯示在Eureka的頁面。
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
spring.application.name=provider-demo
最后分別啟動provider和consumer,在此進入Eureka的頁面,會發現我們的啟動的服務提供者實例和服務消費者實例已經顯示在這個頁面:
負載均衡Ribbon
上文已經將服務注冊到了Eureka但是,服務調用還是采用硬編碼方式,實際到了生產商不可能一直只調用一個服務,也不可能寫IP地址,所以使用ribbon負載均衡組件,使用起來非常簡單,只要在實例化調用服務的RestTemplate地方加上這個注解就行了:@LoadBalanced,使其具有負載均衡的能力,並把下面配置的IP地址改成服務的實例名。然后Controller就變成了這個樣子:
@RestController public class ConsumerController { @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } @Autowired RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; @RequestMapping("/consumer/demo") public String home(User user){ System.out.println(user.toString()); return restTemplate.getForObject("http://provider-demo:8080/provider/demo",String.class); } }
重啟一下Eureka,provider-demo,consumer-demo,分別訪問localhost:7900/provider/demo和http://localhost:8080/consumer/demo應該都能得到 hello cloud 這個結果,說明consumer成功調用了provider中的方法。便解決了不采用硬編碼的方式,使得consumer-demo調用provider-demo接口。
為了驗證負載均衡,我們再啟動一個provider,端口8081,然后在消費者的controller加入如下代碼:
@RequestMapping("/consumer/getInterfaceInfo") public int getInterfaceInfo(){ ServiceInstance choose = loadBalancerClient.choose("provider-demo"); return choose.getPort(); }
可以返回提供者的端口信息,然后再網頁調用該端口,http://localhost:7900/consumer/getInterfaceInfo 多次調用頁面輪流打印 8080 和8081,說明負載均衡實現了,而且默認是輪詢的。ribbon有多種修改負載均衡的策略,可以通過代碼,也可以通過配置文件修改。
服務監控
對於服務的眾多信息可能都需要監控和監聽,SpringCloud主要采用的是下面這個依賴對其實現監聽的:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
在provider配置后啟動項目,打開網頁http://localhost:8081/actuator,會顯示監聽的內容: