javascript
基于SpringBoot 2.0正式版的SpringCloud的微服务实战项目搭建
Spring Cloud簡介
????????Spring Cloud是一個基于Spring Boot實現的云應用開發工具,它為基于JVM的云應用開發中的配置管理、服務發現、斷路器、智能路由、微代理、控制總線、全局鎖、決策競選、分布式會話和集群狀態管理等操作提供了一種簡單的開發方式。
????????Spring Cloud包含了多個子項目(針對分布式系統中涉及的多個不同開源產品),比如:Spring Cloud Config、Spring Cloud Netflix、Spring Cloud CloudFoundry、Spring Cloud AWS、Spring Cloud Security、Spring Cloud Commons、Spring Cloud Zookeeper、Spring Cloud CLI等項目。
????????本文將介紹基于springBoot2.0正式版的springCloud的微服務搭建以及需要注意的細節.
?
1.服務注冊與發現
????????在簡單介紹了Spring Cloud和微服務架構之后,下面回歸本文的主旨內容,如何使用Spring Cloud搭建服務注冊與發現模塊。
????????這里我們會用到Spring Cloud Netflix,該項目是Spring Cloud的子項目之一,主要內容是對Netflix公司一系列開源產品的包裝,它為Spring Boot應用提供了自配置的Netflix OSS整合。通過一些簡單的注解,開發者就可以快速的在應用中配置一下常用模塊并構建龐大的分布式系統。它主要提供的模塊包括:服務發現(Eureka),斷路器(Hystrix),智能路有(Zuul),客戶端負載均衡(Ribbon)等。
????????所以,我們這里的核心內容就是服務發現模塊:Eureka。下面我們動手來做一些嘗試。
創建“服務注冊中心”
?1.1?創建springboot項目
?????????http://start.spring.io/ 自定義spring boot在線maven構建工具很方便(默認2.0版本)?
1.2 修改pom文件,添加spring cloud 依賴如下
<dependencies><!-- springCloud 配置 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency> <!-- springCloud注測中心服務 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</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>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>?
紅色標記部分和2.0之前的版本有區別一定要注意:
2.0之前的版本為:
<dependencies> <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-server</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RELEASE</version><type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>?
1.3 在啟動類上加上注解 如下
????????通過@EnableEurekaServer注解啟動一個服務注冊中心提供給其他應用進行對話。這一步非常的簡單,只需要在一個普通的Spring Boot應用中添加這個注解就能開啟此功能,比如下面的例子:
@SpringBootApplication @EnableEurekaServer public class Demo5Application {public static void main(String[] args) {SpringApplication.run(Demo5Application.class, args);} }?
1.4 配置文件application.properties
????????在默認設置下,該服務注冊中心也會將自己作為客戶端來嘗試注冊它自己,所以我們需要禁用它的客戶端注冊行為,只需要在application.properties中問增加如下配置:
#注冊中心服務ID spring.application.name=compute-server#端口號 server.port=1111 # eureka.client.registerWithEureka :表示是否將自己注冊到Eureka Server,默認為true。 # 由于當前這個應用就是Eureka Server,故而設為false eureka.client.register-with-eureka=false # eureka.client.fetchRegistry :表示是否從Eureka Server獲取注冊信息,默認為true。因為這是一個單點的Eureka Server, # 不需要同步其他的Eureka Server節點的數據,故而設為false。 eureka.client.fetch-registry=false # eureka.client.serviceUrl.defaultZone :設置與Eureka Server交互的地址,查詢服務和注冊服務都需要依賴這個地址。默認是 eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/?
1.5配置文件application.properties
?
????????為了與后續要進行注冊的服務區分,這里將服務注冊中心的端口通過server.port屬性設置為1111。
啟動工程后,訪問:http://localhost:1111/
可以看到下面的頁面,其中還沒有發現任何服務:
?
2.搭建服務端
? ? 2.1 創建springboot項目同上
? ? 2.2?修改pom.xml文件,添加spring cloud 依賴如下(紅色標記一定要添加)
????????<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency> </dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>?
2.3 在啟動類上加上注解 如下
????????最后在主類中通過加上@EnableEurekaClient?注解,該注解能激活Eureka中的對注冊中心注冊服務實現,才能實現Controller中對服務信息的輸出。
@SpringBootApplication @EnableEurekaClient public class Demo3Application {public static void main(String[] args) {SpringApplication.run(Demo3Application.class, args);} }?
2.4 配置文件application.properties
#服務名稱 spring.application.name=compute-service1 #端口號 server.port=2222 #在注冊中心中進行注冊 eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ #啟動服務發現的功能,開啟了才能調用其它服務 spring.cloud.config.discovery.enabled=true #發現的服務的名字--對應注測中心的服務名字 spring.cloud.config.discovery.serviceId=compute-server?
? ? ? ? 通過spring.application.name屬性,我們可以指定微服務的名稱后續在調用的時候只需要使用該名稱就可以進行服務的訪問。
????eureka.client.serviceUrl.defaultZone屬性對應服務注冊中心的配置內容,指定服務注冊中心的位置。
??????????為了在本機上測試區分服務提供方和服務注冊中心,使用server.port屬性設置不同的端口。
2.5 啟動該項目
????? ? 再次訪問:http://localhost:1111/
????? ? 可以看到,我們定義的服務被注冊了。如下圖所示:
?
?
3 spring cloud 路由網關服務---Zuul
????????在使用Zuul之前,我們先構建一個服務注冊中心、以及兩個簡單的服務,比如:我構建了一個service-A,一個service-B。然后啟動eureka-server和這兩個服務。通過訪問eureka-server,我們可以看到service-A和service-B已經注冊到了服務中心。
服務service-A和service-B的配置都一樣并實現在注冊中心注冊,只有端口號不一樣而已如下所示:
service-A:
并在service-A:下構建一個controller如下:
package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;@RestController public class MyController {@RequestMapping(value = "/info" ,method = RequestMethod.GET)public String info() { return "hello I am is spring-serviceA"; //測試代碼直接返回一個字符串,不再調用service層等等。 } }?
service-B:
并在service-B下構建一個controller如下:
package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;@RestController public class MyController {@RequestMapping(value = "/info" ,method = RequestMethod.GET)public String info() { return "hello I am is spring-service"; //測試代碼直接返回一個字符串,不再調用service層等等。 } }?
? ? 3.1 創建 spring boot項目 同上
? ? 3.2?修改pom.xml文件,添加spring cloud 依賴如下
<dependencies><!-- springBoot 核心 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>?
3.3 在啟動類上加上注解 如下
- 應用主類使用@EnableZuulProxy注解開啟Zuul
- 這里用了@SpringCloudApplication注解,之前沒有提過,通過源碼我們看到,它整合了@SpringBootApplication、@EnableEurekaClient、@EnableCircuitBreaker,主要目的還是簡化配置。這幾個注解的具體作用這里就不做詳細介紹了,之前的文章已經都介紹過。 @EnableZuulProxy
@SpringCloudApplication
public class Demo4Application {public static void main(String[] args) {SpringApplication.run(Demo4Application.class, args);}
}
?
3.4 配置文件application.properties
application.properties中配置eureka服務注冊中心
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ server.port=3333 spring.application.name=service-zuul #表示只要訪問以/api-a/開頭的多層目錄都可以路由到 id為compute-service的服務上 zuul.routes.compute-service=/api-a/**?
?
#表示只要訪問以/api-a/開頭的多層目錄都可以路由到 id為compute-service1的服務上
zuul.routes.compute-service1=/api-a/**
上面的一行等同于下面的兩行
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=compute-service1
| ? | 匹配任意單個字符 | /feign-consumer/? | 匹配/feign-consumer/a,/feign-consumer/b,/feign-consumer/c等 |
| * | 匹配任意數量的字符 | /feign-consumer/* | 匹配/feign-consumer/aaa,feign-consumer/bbb,/feign-consumer/ccc等,無法匹配/feign-consumer/a/b/c |
| ** | 匹配任意數量的字符 | /feign-consumer/* | 匹配/feign-consumer/aaa,feign-consumer/bbb,/feign-consumer/ccc等,也可以匹配/feign-consumer/a/b/c |
? 3.4 啟動項目 測試
輸入地址:http://localhost:4444/api-a/info
每次刷新訪問都會在下面結果輪詢顯示:
?
這就簡單實現了springCloud的負載均衡.
?
? 3.5 服務過濾
????????在完成了服務路由之后,我們對外開放服務還需要一些安全措施來保護客戶端只能訪問它應該訪問到的資源。所以我們需要利用Zuul的過濾器來實現我們對外服務的安全控制。
????????在服務網關中定義過濾器只需要繼承ZuulFilter抽象類實現其定義的四個抽象函數就可對請求進行攔截與過濾。
????????比如下面的例子,定義了一個Zuul過濾器,實現了在請求被路由之前檢查請求中是否有accessToken參數,若有就進行路由,若沒有就拒絕訪問,返回401 Unauthorized錯誤。
package com.example.demo.filter;import javax.servlet.http.HttpServletRequest;import org.springframework.util.StringUtils;import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext;public class AccessFilter extends ZuulFilter {@Overridepublic Object run() {RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest();System.out.println(String.format("%s demoFilter request to %s", request.getMethod(), request.getRequestURL().toString()));String username = request.getParameter("username");// 獲取請求的參數 if(!StringUtils.isEmpty(username)&&username.equals("lilei")){//通過ctx.setSendZuulResponse(true);// 對該請求進行路由 ctx.setResponseStatusCode(200); ctx.set("isSuccess", true);// 設值,讓下一個Filter看到上一個Filter的狀態 return null; }else{ctx.setSendZuulResponse(false);// 過濾該請求,不對其進行路由 ctx.setResponseStatusCode(401);// 返回錯誤碼 ctx.setResponseBody("{\"result\":\"username is not correct!\"}");// 返回錯誤內容 ctx.set("isSuccess", false); return null;}}@Overridepublic boolean shouldFilter() {return true;// 是否執行該過濾器,此處為true,說明需要過濾 }@Overridepublic int filterOrder() {return 0;// 優先級為0,數字越大,優先級越低 }/*pre:可以在請求被路由之前調用route:在路由請求時候被調用post:在route和error過濾器之后被調用error:處理請求時發生錯誤時被調用*/@Overridepublic String filterType() {return "pre";// 前置過濾器 }}?
自定義過濾器的實現,需要繼承ZuulFilter,需要重寫實現下面四個方法:
- filterType:返回一個字符串代表過濾器的類型,在zuul中定義了四種不同生命周期的過濾器類型,具體如下:
- pre:可以在請求被路由之前調用
- routing:在路由請求時候被調用
- post:在routing和error過濾器之后被調用
- error:處理請求時發生錯誤時被調用
- filterOrder:通過int值來定義過濾器的執行順序
- shouldFilter:返回一個boolean類型來判斷該過濾器是否要執行,所以通過此函數可實現過濾器的開關。在上例中,我們直接返回true,所以該過濾器總是生效。
- run:過濾器的具體邏輯。需要注意,這里我們通過ctx.setSendZuulResponse(false)令zuul過濾該請求,不對其進行路由,然后通過ctx.setResponseStatusCode(401)設置了其返回的錯誤碼,當然我們也可以進一步優化我們的返回,比如,通過ctx.setResponseBody(body)對返回body內容進行編輯等。
在實現了自定義過濾器之后,還需要實例化該過濾器才能生效,我們只需要在應用主類中增加如下內容:
再次訪問鏈接:http://localhost:4444/api-a/info
提示如下錯誤:被過濾器給攔截了
訪問新地址:http://localhost:4444/api-a/info?username=lilei
則可以正常訪問
項目源碼:https://download.csdn.net/download/guokezhongdeyuzhou/10303861
由于時間原因暫時更新到此,后面會陸續更新相關的其他特性.
轉載于:https://www.cnblogs.com/powerwu/articles/9767878.html
總結
以上是生活随笔為你收集整理的基于SpringBoot 2.0正式版的SpringCloud的微服务实战项目搭建的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mongdb group聚合操作
- 下一篇: 12-order by和group by