沒有廢話,直接上干貨,理論部分大家可以看其它資料。
這里是部分關鍵代碼,如果需要全部可運行的代碼,請給本人留言。
在后繼,還將給出搭建高可用Eureka架構的方式。
1 Eureka的框架圖
在Eureka的服務器里,包含着記錄當前所有服務列表的注冊中心,而服務提供者和調用者所在的機器均被稱為“Eureka客戶端”。
服務提供者會和服務器進行如下的交互:第一,注冊本身能提供的服務,第二,定時發送心跳,以此證明本服務處於生效狀態。而服務調用者一般會從服務器查找服務,並根據找到的結果從服務提供者這端調用服務。
2.1搭建Eureka服務器
這里我們將在EurekaBasicDemo-Server項目里編寫Eureka服務器的代碼。
第一步,當我們創建完Maven類型的項目后,需要在pom.xml里編寫該項目所需要的依賴包,關鍵代碼如下。
1 <dependencyManagement>
2 <dependencies>
3 <dependency>
4 <groupId>org.springframework.cloud</groupId>
5 <artifactId>spring-cloud-dependencies</artifactId>
6 <version>Brixton.SR5</version>
7 <type>pom</type>
8 <scope>import</scope>
9 </dependency>
10 </dependencies>
11 </dependencyManagement>
12 <dependencies>
13 <dependency>
14 <groupId>org.springframework.cloud</groupId>
15 <artifactId>spring-cloud-starter-eureka-server</artifactId>
16 </dependency>
17 </project>
從第1到第11行,我們引入了版本號是Brixton.SR5的Spring Cloud包,這個包里包含着Eureka的支持包,在第13到16行的代碼里,引入了Eureka Server端的支持包,引入后,我們才能在項目的java文件里使用Eureka的特性。
第二步,在application.yml里,需要配置Eureka服務端的信息,代碼如下。
1 server: 2 port: 8888 3 eureka: 4 instance: 5 hostname: localhost 6 client: 7 register-with-eureka: false 8 fetch-registry: false 9 serviceUrl: 10 defaultZone: http://localhost:8888/eureka/
從第2和第5行里,我們指定了Eureka服務端使用的主機地址和端口號,這里分別是localhost和8888,也就是說讓服務端運行在本地8888號端口,在第10行里,我們指定了服務端所在的url地址。
由於這已經是服務器端,所以我們通過第7行的代碼,指定無需向Eureka注冊中心注冊自己,同理,服務器端的職責是維護服務列表而不是調用服務,所以通過第8行的代碼指定本端無需檢索服務。
第三步,在RegisterCenterApp.java里編寫Eureka啟動代碼。
1 省略必要的package和import代碼 2 @EnableEurekaServer //指定本項目是Eureka服務端 3 @SpringBootApplication 4 public class RegisterCenterApp 5 { 6 public static void main( String[] args ) 7 {SpringApplication.run(RegisterCenterApp.class, args);} 8 }
在第6行的main函數里,我們還是通過run方法啟動Eureka服務。
運行App.java啟動Eureka服務器端后,在瀏覽器里輸入localhost:8888后,可以看到如下圖所示的Eureka服務器端的信息面板,其中Instances currently registered with Eureka目前是空的,說明尚未有服務注冊到本服務器的注冊中心。
2.2 編寫作為服務提供者的Eureka客戶端
這里我們將在EurekaBasicDemo-ServerProvider項目里編寫Eureka客戶端的代碼,在這個項目里,我們將提供一個SayHello的服務。
第一步,創建完Maven類型的項目后,我們需要在pom.xml里寫入本項目的依賴包,關鍵代碼如下。本項目所用到的依賴包之前都用過,所以這里就不展開講了。
1 <dependencyManagement>
2 <dependencies>
3 <dependency>
4 <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId>
5 <version>Brixton.SR5</version>
6 <type>pom</type>
7 <scope>import</scope>
8 </dependency>
9 </dependencies>
10 </dependencyManagement>
11 <dependencies>
12 <dependency>
13 <groupId>org.springframework.boot</groupId>
14 <artifactId>spring-boot-starter-web</artifactId>
15 <version>1.5.4.RELEASE</version>
16 </dependency>
17 <dependency>
18 <groupId>org.springframework.cloud</groupId>
19 <artifactId>spring-cloud-starter-eureka</artifactId>
20 </dependency>
21 </dependencies>
第二步,在application.yml里編寫針對服務提供者的配置信息,代碼如下。
1 server: 2 port: 1111 3 spring: 4 application: 5 name: sayHello 6 eureka: 7 client: 8 serviceUrl: 9 defaultZone: http://localhost:8888/eureka/
從第2行里,我們能看到本服務將啟用1111號端口,在第5行,我們指定了本服務的名字,叫sayHello,在第9行,我們把本服務注冊到了Eureka服務端,也就是注冊中心里。
第三步,在Controller.java里,編寫控制器部分的代碼,在其中實現對外的服務。
1 //省略必要的package和import代碼 2 @RestController //說明這是個控制器 3 public class Controller { 4 @Autowired //描述Eureka客戶端信息的類 5 private DiscoveryClient client; 6 @RequestMapping(value = "/hello/{username}", method = RequestMethod.GET ) 7 public String hello(@PathVariable("username") String username) { 8 ServiceInstance instance = client.getLocalServiceInstance(); 9 //輸出服務相關的信息 10 System.out.println("host is:" + instance.getHost()); 11 System.out.println("port is:" + instance.getPort()); 12 System.out.println("ServiceID is:" + instance.getServiceId() ); 13 //返回字符串 14 return "hello " + username; 15 } 16 }
我們通過第6和第7行的代碼,指定了能觸發hello方法的url格式,在這個方法里,我們首先通過第10到12行的代碼,輸出了主機名、端口號和ServiceID等信息,並在第14行里,返回了一個字符串。
第四步,編寫Spring Boot的啟動類ServiceProviderApp.java,代碼如下。
1 //省略必要的package和import代碼 2 @SpringBootApplication 3 @EnableEurekaClient 4 public class ServiceProviderApp { 5 public static void main( String[] args ) 6 {SpringApplication.run(ServiceProviderApp.class, args);} 7 }
由於這是處於Eureka的客戶端,所以加入第3行所示的注解,在main函數里,我們依然是通過run方法啟動Spring Boot服務。
2.3 編寫服務調用者的代碼
啟動Eureka服務器端的RegisterApp.java和服務提供者端的ServiceProviderApp.java,在瀏覽器里輸入http://localhost:8888/后,在Eureka的信息面板里能看到SayHello服務,如下圖所示。
如果這時我們在瀏覽器里輸入http://localhost:1111/hello/Mike,能直接調用服務,同時能看瀏覽器里看到“hello Mike”的輸出。不過在大多數的場景里,我們一般是在程序里調用服務,而不是簡單地通過瀏覽器調用,在下面的EurekaBasicDemo-ServiceCaller項目里,我們將演示在Eureka客戶端調用服務的步驟。
第一步。在這個Maven項目里,我們編寫如下的pom.xml配置,關鍵代碼如下。
1 <dependencyManagement> 2 <dependencies> 3 <dependency> 4 <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId> 5 <version>Brixton.SR5</version> 6 <type>pom</type> 7 <scope>import</scope> 8 </dependency> 9 </dependencies> 10 </dependencyManagement> 11 <dependencies> 12 <dependency> 13 <groupId>org.springframework.boot</groupId> 14 <artifactId>spring-boot-starter-web</artifactId> 15 <version>1.5.4.RELEASE</version> 16 </dependency> 17 <dependency> 18 <groupId>org.springframework.cloud</groupId> 19 <artifactId>spring-cloud-starter-eureka</artifactId> 20 </dependency> 21 <dependency> 22 <groupId>org.springframework.cloud</groupId> 23 <artifactId>spring-cloud-starter-ribbon</artifactId> 24 </dependency> 25 </dependencies>
請大家注意,從第21到24行,我們需要引入 ribbon的依賴包,通過它我們可以實現負載均衡。而其它的依賴包我們之前都已經見過,所以就不再解釋了。
第二步,在application.yml里,我們編寫針對本項目的配置信息,代碼如下。
1 spring: 2 application: 3 name: callHello 4 server: 5 port: 8080 6 eureka: 7 client: 8 serviceUrl: 9 defaultZone: http://localhost:8888/eureka/
在第3行里,我們指定了本服務的名字叫callHello,在第5行里我們指定了本服務是運行在8080端口,在第9行里,我們把本服務注冊到Eureka服務器上。
第三步,編寫提供服務的控制器類,在其中調用服務提供者的提供的服務,代碼如下。
1 //省略必要的package和import代碼 2 @RestController 3 @Configuration 4 public class Controller { 5 @Bean 6 @LoadBalanced 7 public RestTemplate getRestTemplate() 8 { return new RestTemplate(); } 9 10 @RequestMapping(value = "/hello", method = RequestMethod.GET ) 11 public String hello() { 12 RestTemplate template = getRestTemplate(); 13 String retVal = template.getForEntity("http://sayHello/hello/Eureka", String.class).getBody(); 14 return "In Caller, " + retVal; 15 } 16 }
在第7行的getRestTemplate方法上,我們啟動了@LoadBalanced(負載均衡)的注解。關於負載均衡的細節將在后面章節里詳細描述,這里我們引入@LoadBalanced注解的原因是,RestTemplate類型的對象本身不具備調用遠程服務的能力,也就是說,如果我們去掉這個注解,程序未必能跑通。只有當我們引入該注解,該方法所返回的對象才能具備調用遠程服務的能力。
在提供服務的第11行的hello方法里,我們是通過第13行的代碼,用RestTemplate類型對象的getForEntity方法,調用服務提供者sayHello提供的hello方法。
這里我們是通過http://sayHello/hello/Eureka這個url去發現對應的服務,在這個url里,只包含了服務名sayHello,並沒有包含服務所在的主機名和端口號,換句話說,該url其實是通過注冊中心定位到sayHello服務的物理位置的。
至於這個url和該服務物理位置的綁定關系,是在Eureka內部實現的,這也是Eureka可以被稱作“服務發現框架”的原因。
第四步,在ServiceCallerApp.java方法里,我們編寫啟動本服務的代碼,這我們已經很熟悉了,所以就不再講述了。
1 //省略必要的package和import代碼 2 @EnableDiscoveryClient 3 @SpringBootApplication 4 public class ServiceCallerApp 5 { 6 public static void main( String[] args ) 7 {SpringApplication.run(ServiceCallerApp.class, args); } 8 }
2.4 通過服務調用者調用服務
當我們依次啟動Eureka服務器(也就是注冊中心)、服務提供者和服務調用者的Spring Boot啟動程序后,在瀏覽器里輸入http://localhost:8888/后,能在信息面板里看到有兩個服務,分別是服務提供者SayHello和服務調用者CallHello,如下圖所示。
由於服務調用者運行在8080端口上,所以如果我們在瀏覽器里輸入http://localhost:8080/hello,能看到在瀏覽器里輸出“In Caller, hello Eureka”,這就說明它確實已經調用了服務提供者SayHello里的hello方法。
此外,我們還能在服務提供者所在的控制台里看到host、port和ServiceID的輸出,如下圖所示,這能進一步驗證了服務提供者里控制器類里的hello方法被服務調用者調到。