一、Eureka的作用
這里先簡單說明使用eureka進行業務層隔離,實現項目服務化也可以理解為微服務,我一直崇尚先實現代碼再學習理論,先簡單上手進行操作,eureka使用分為三塊,1是服務注冊中心,2是服務生產模塊,3是服務消費模塊
關系調用說明:
- 服務生產者啟動時,向服務注冊中心注冊自己提供的服務
- 服務消費者啟動時,在服務注冊中心訂閱自己所需要的服務
- 注冊中心返回服務提供者的地址信息給消費者
- 消費者從提供者中調用服務
Eureka包含了Server端和Client端組件。
Server端是服務注冊中心,用於提供服務的注冊與發現。Eureka支持高可用的配置,當集群中有分片出現故障時,Eureka就會轉入自動保護模式,它允許分片故障期間繼續提供服務的發現和注冊,當故障分片恢復正常時,集群中其他分片會把他們的狀態再次同步回來。
Client端組件包含服務消費者與服務生產者。在應用程序運行時,Eureka服務生產者會向注冊中心注冊自身提供的服務並每30s發送心跳來更新它的服務租約,當一段時間生產者沒有向服務中心續租將會被移出服務提供注冊表。同時也可以從服務端查詢當前注冊的服務信息並把他們緩存到本地並周期性的刷新服務狀態。
二、搭建eurkea服務注冊中心
新建Project或者Module,選擇Maven結構
簡單看一下我的模塊結構
1、修改pom.xml文件,增加springboot和springcloud的配置,由於使用的最新的spring boot所以spring cloud也是使用最新版本,注意這里的version是Finchley.RELEASE
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
2、新建resources文件夾並在File -> Project Structure 中設置為Resources格式,並增加application.yml格式文件,也可用properties格式
spring: application: #Eureka服務注冊中心名稱 name: javademo-tyh-eureka-server server: #服務注冊中心端口號 port: 11000 eureka: instance: #服務注冊中心主機名 hostname: localhost client: #是否向服務注冊中心注冊自己 register-with-eureka: false #是否檢索服務 fetch-registry: false #服務注冊中心的地址 service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3、在main方法的類中增加@EnableEurekaServer注解來標明是服務注冊中心,從main方法中寫spring boot的運行代碼
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class AppEureka { public static void main( String[] args ) { SpringApplication.run(AppEureka.class, args); } }
OK,現在eurkea的服務注冊中心就配置完畢了,從main這里啟動一下,瀏覽器中訪問http://localhost:11000就能看到運行狀態界面了,如果端口號沖突自己修改一下即可
現在可以在"Instances currently registered with Eureka"中看到沒有任何服務注冊進來。
三、搭建服務生產模塊
新建Module,選擇Maven的QuickStart模板當作服務生產者,先看我的目錄結構,沒有用的文件我都打了馬賽克了
1、修改pom.xml文件,增加spring boot和spring cloud節點,注意在dependencies的cloud節點下增加了exclusions節點指明與注冊中心的通信協議,否則可能無法注冊服務
<dependencyManagement> <dependencies> <dependency> <!-- Import dependency management from Spring Boot --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <!-- 設置與注冊中心的通信協議,否則有可能提示錯誤“拒絕注冊服務” --> <exclusions> <exclusion> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> </exclusion> <exclusion> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> </exclusion> <exclusion> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-apache-client4</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
2、新建resources文件夾並在File -> Project Structure 中設置為Resources格式,並增加application.yml格式文件
#設置提供的服務名 spring: application: name: javademo-tyh-service-base #服務注冊中心地址(剛剛搭建的Eureka Server的地址) eureka: client: service-url: defaultZone: http://localhost:11000/eureka #設置自己啟動的端口 server: port: 12000
3、在main方法的類中增加@EnableEurekaClient注解來標明是服務客戶端,從main方法中寫spring boot的運行代碼
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @EnableEurekaClient @SpringBootApplication public class AppServiceBase { public static void main( String[] args ) { SpringApplication.run(AppServiceBase.class,args); } }
4、編寫各自提供服務的Controller和Action,新建一個controller文件夾,建立UserController類,編寫服務方法,重要的是增加一個private DiscoveryClient對象來自動注入服務方法,自己新建一個Model模塊存儲實體
import javademo.tyh.model.base.UserModelEx; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @Controller @RequestMapping("/user") public class UserController { @Autowired private DiscoveryClient client; @ResponseBody @RequestMapping("/list") public List<UserModelEx> list() { UserModelEx modelEx = new UserModelEx(); modelEx.setId(100); modelEx.setUsername("taiyonghai"); modelEx.setPassword("111111"); modelEx.setSex(1); modelEx.setSexString("男"); modelEx.setAge(30); modelEx.setCreateTime(LocalDateTime.now()); List<UserModelEx> list = new ArrayList<>(); list.add(modelEx); return list; } @ResponseBody @RequestMapping("/get") public UserModelEx get( int id ) { System.out.println("接收參數:" + id); UserModelEx modelEx = new UserModelEx(); modelEx.setId(id); modelEx.setUsername("taiyonghai"); modelEx.setPassword("111111"); modelEx.setSex(1); modelEx.setSexString("男"); modelEx.setAge(30); return modelEx; } }
OK,現在一個服務生產者就搭建完畢,我們先啟動eurkea服務注冊中心http://localhost:11000,再啟動服務生產者http://localhost:12000如果端口被占用自行更換
可以看到我們剛剛搭建的服務已經被注冊進來了,下面直接訪問剛剛提供服務的action看看響應結果http://localhost:12000/user/list,有數據生產者搭建完畢。
四、搭建服務消費模塊
新建Module,選擇Maven的QuickStart模板當作服務消費者,先看我的目錄結構
1、修改pom.xml文件,增加spring boot和spring cloud節點,由於eureka很大程度上都跟spring boot有關系,所以基本每個端都需要配spring boot,消費者這邊使用Ribbon進行客戶端負載均衡
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- import spring cloud eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <!-- import spring boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
2、新建resources文件夾並在File -> Project Structure 中設置為Resources格式,並增加application.yml格式文件
#設置自己的程序名稱 spring: application: name: javademo-tyh-web-base #thymeleaf 配置 thymeleaf: encoding: UTF-8 prefix: classpath:/templates cache: false #服務注冊中心地址(剛剛搭建的Eureka Server的地址) eureka: client: #是否向服務中心注冊自己 register-with-eureka: false #設置eureka服務中心的地址 service-url: defaultZone: http://localhost:11000/eureka #設置自己啟動的端口 server: port: 13000
3、在main方法的類中增加@EnableDiscoveryClient注解來標明是服務客戶端,從main方法中寫spring boot的運行代碼
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient @EnableAutoConfiguration public class AppWebBase { public static void main( String[] args ) { SpringApplication.run(AppWebBase.class, args); } @Bean @LoadBalanced //客戶端負載均衡 public RestTemplate restTemplate(){ return new RestTemplate(); } }
4、編寫消費者的Controller和Action,新建一個controller文件夾,建立UserController類,編寫服務方法,重要的是增加一個private RestTemplate對象來調用服務生產者
import javademo.tyh.model.base.UserModelEx; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.client.RestTemplate; import java.util.List; @RequestMapping("/user") @Controller public class UserController { //自動獲取RestTemplate @Autowired private RestTemplate restTemplate; @RequestMapping("/list") public String list( Model model ) { //泛型集合先指定內部對象類型 ParameterizedTypeReference<List<UserModelEx>> paramType = new ParameterizedTypeReference<List<UserModelEx>>() {}; //由於沒有請求參數,所以直接RestTemplate.exchange()調取接口,使用ResponseEntity獲取響應對象 //第一個參數是服務名稱及服務地址 ResponseEntity<List<UserModelEx>> responseEntity = restTemplate.exchange("http://javademo-tyh-service-base/user/list", HttpMethod.POST, null, paramType); //ResponseEntity指明了泛型數據,所以直接調用getBody()方法會自動序列化為此對象 List<UserModelEx> list = responseEntity.getBody(); model.addAttribute("models", list); return "/user/list"; } @RequestMapping("/get") public String get(Model model) { //服務接口請求參數對象,並填充參數 MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("id", "555"); //聲明請求實體HttpEntity,並填入請求參數 HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, null); //由於返回對象不是泛型,所以也不需要先獲取內部類型,直接調用並傳遞請求對象 //第一個參數是服務名稱及服務地址 ResponseEntity<UserModelEx> responseEntity = restTemplate.exchange("http://javademo-tyh-service-base/user/get", HttpMethod.POST, requestEntity, UserModelEx.class); //自動序列化返回對象 UserModelEx modelEx = responseEntity.getBody(); model.addAttribute("modelEx", modelEx); return "/user/get"; } }
5、建立對應action的頁面,並把獲取到的內容渲染到頁面中,在resources下建立templates/user文件夾,創建list頁面填入以下內容
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>this is /user/list</h1> <table border="1px"> <tr th:each="item : ${models}"> <td th:text="${item.Id}">id</td> <td th:text="${item.Username}">username</td> <td th:text="${item.Password}">password</td> <td th:text="${item.Sex}">sex</td> <td th:text="${item.Age}">age</td> <td th:text="${item.CreateTime}">createtime</td> </tr> </table> </body> </html>
OK,現在一個服務消費者就搭建完畢,可以運行打開瀏覽器http://localhost:13000/user/list來查看是否調用成功
到此整個Eurkea的服務注冊中心、服務生產者、服務消費者都搭建完畢,后面再根據文檔查看詳細的高可用配置等,加深一下對該技術的了解。