對在Spring Cloud Alibaba使用nacos做注冊和動態(tài)配置中心,Feign遠程調用绽榛,并實現負載均衡的學習過程做一下總結湿酸,希望大家共同進步。
一. 安裝nacos服務
具體安裝步驟可參考這篇博客:
https://blog.csdn.net/qq_32352777/article/details/86560333
寫的很不錯灭美,感謝作者推溃。-
安裝問題總結
測試環(huán)境一般建議安裝單機版的,簡單快速届腐。集群安裝的話铁坎,為了符合高可用的要求蜂奸,MySQL也需要安裝成集群形式。如Master-Slave模式硬萍。
-
如果是在虛擬機上安裝扩所,一般的虛擬機我們不會給分配太大內存。所以我們得根據自己的機子內存情況修改一下nacos啟動時默認分配的虛擬機內存朴乖,否則會啟動失敗祖屏,我們去查看nacos的安裝目錄下的log目錄的nacos.log日志,會發(fā)現報內存不足的異常买羞。
(1)在nacos安裝目錄下袁勺,打開nacos啟動腳本。
vim bin/startup.sh
(2)vim模式下ctrl+f向后翻頁畜普,找到如下部分
(3)根據實際情況進行對nacos啟動jvm虛擬機內存設置進行修改期丰。
二. 代碼實現
-
創(chuàng)建父項目
父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> <groupId>com.test</groupId> <artifactId>cloud-test</artifactId> <version>0.0.1-SNAPSHOT</version> <name>cloud-test</name> <packaging>pom</packaging> <!--子模塊--> <modules> <module>cloud-service1</module> <module>cloud-service2</module> <module>cloud-consumer</module> <module>cloud-common</module> </modules> <!--依賴的組件的大版本號--> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.RELEASE</spring-cloud.version> <spring-cloud-alibaba.version>0.9.0.RELEASE</spring-cloud-alibaba.version> <spring-boot-starter-parent.version>2.2.2.RELEASE</spring-boot-starter-parent.version> </properties> <!--依賴jar包版本管理--> <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> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>${spring-boot-starter-parent.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!--服務發(fā)現(注冊中心)--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--配置中心--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>LATEST</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
項目結構圖:
-
創(chuàng)建公共子模塊
公共做模塊是放服務調用的接口和一些公共實體類和公共工具的漠嵌。結構如下:
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> <artifactId>cloud-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>cloud-consumer</name> <packaging>jar</packaging> <parent> <groupId>com.test</groupId> <artifactId>cloud-test</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>com.test</groupId> <artifactId>cloud-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> </project>
創(chuàng)建一個測試的實體類User
package com.common.model; import lombok.Data; /** * Author: yhl * DateTime: 2019/12/8 23:13 * Description: write some description */ @Data public class User { private Long id; private String name; private String url; }
創(chuàng)建微服務調用的接口IUserService
package com.common.service; import com.common.model.User; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import java.util.Map; /** * Author: yhl * DateTime: 2019/12/8 23:13 * Description: write some description */ public interface IUserService { @RequestMapping("/testOut") Map<Object,Object> test(@RequestParam("name") String name); @RequestMapping("/testOutObj") User testObj(@RequestBody User user); @RequestMapping("/testNacosDynamicProp") String testNacosDynamicProp(); }
配置文件application.yml可以放置一些公共的參數配置咐汞,比如加解密私鑰等等
-
創(chuàng)建服務提供者
此模塊為服務提供方,實現真正的業(yè)務邏輯儒鹿。結構如下:
為了測試Feign的負載均衡化撕,創(chuàng)建兩個一樣結構和內容的服務提供者,分別命名為cloud-service1和cloud-service2约炎,在它們各自的application.yml中植阴,使用不同的端口號來模擬不同地址的相同的服務。
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>com.test</groupId> <artifactId>cloud-test</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>cloud-service1</artifactId> <version>0.0.1-SNAPSHOT</version> <name>cloud-service1</name> <packaging>jar</packaging> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--引入公共模塊--> <dependency> <groupId>com.test</groupId> <artifactId>cloud-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>
創(chuàng)建配置文件bootstrap.yaml和application.yml
bootstrap.yml如下:
spring: application: # 服務提供者名稱 name: cloud-service cloud: nacos: discovery: # 服務注冊于發(fā)現地址 server-addr: 192.168.31.217:8848 config: # 配置中心地址 server-addr: ${spring.cloud.nacos.discovery.server-addr} # 配置中心配置文件的格式圾浅,如果不設置此項掠手,默認為.properties格式 file-extension: yaml
application.yml如下:
#服務端口,這里我們設置cloud-service1為8001狸捕,cloud-service2為8002 server: port: 8081
有了application.yml喷鸽,為什么還要創(chuàng)建一個bootstrap.yml呢,它們倆的區(qū)別如下:
https://blog.csdn.net/ThinkWon/article/details/100007093
感謝這篇文章的作者灸拍,解開了我的迷惑做祝。
創(chuàng)建啟動類ServiceApplication1
package com.service; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication public class ServiceApplication1 { public static void main(String[] args) { SpringApplication.run(ServiceApplication1.class, args); } }
創(chuàng)建服務提供類UserServiceProvider
package com.service.controller; import com.common.model.User; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; /** * Author: yhl * DateTime: 2019/12/8 23:17 * Description: write some description */ @RestController public class UserServiceProvider { @RequestMapping("/testOut") public Map test(@RequestParam("name") String name, HttpServletRequest req) { Map<Object, Object> map = new HashMap<>(); map.put("url", req.getRequestURL().toString()); map.put("name", name); return map; } @RequestMapping("/testOutObj") public User testObj(@RequestBody() User user, HttpServletRequest req) { user.setUrl(req.getRequestURL().toString()); return user; } }
服務提供者創(chuàng)建完成。
-
創(chuàng)建服務消費者cloud-consumer
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> <artifactId>cloud-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>cloud-consumer</name> <packaging>jar</packaging> <parent> <groupId>com.test</groupId> <artifactId>cloud-test</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>com.test</groupId> <artifactId>cloud-common</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!-Feign---> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> </project>
因為遠程調用使用的是Feign組件,所以pom中加了Feign的依賴鸡岗。
創(chuàng)建配置文件bootstrap.yaml和application.yml
bootstrap.yml如下:
spring: application: # 服務提供者名稱 name: cloud-consumer cloud: nacos: discovery: # 服務注冊于發(fā)現地址 server-addr: 192.168.31.217:8848 config: # 配置中心地址 server-addr: ${spring.cloud.nacos.discovery.server-addr} # 配置中心配置文件的格式混槐,如果不設置此項,默認為.properties格式 file-extension: yaml
application.yml如下:
#服務端口轩性,這里我們設置cloud-service1為8001声登,cloud-service2為8002 server: port: 8080
創(chuàng)建服務消費者啟動類ConsumerApplication
package com.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients//開啟feign public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
在啟動類上加@EnableFeignClients,代表開啟了對feign組件的支持。
繼承服務提供方接口UserService
@FeignClient(name ="cloud-service") public interface UserService extends IUserService { }
此接口方法繼承了我們在common模塊定義的微服務接口悯嗓,加上@FeignClient注解之后件舵,表示可使用Feign來調用此接口中方法中@RequestMapping映射路徑的服務提供者的http服務。
此接口是我抽象出來的绅作,目的是不用在common模塊中也引入Feign的依賴芦圾,當然也可以不用這么寫。直接在IUserService接口加上@FeignClient注解俄认。@FeignClient中的name屬性配置的為bootstrap.yml中配置的服務提供者名稱。
創(chuàng)建消費者接口UserConsumerController
package com.consumer.controller; import com.common.model.User; import com.consumer.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; /** * Author: yhl * DateTime: 2019/12/8 23:12 * Description: write some description */ @RestController public class UserConsumerController { @Autowired private UserService userService; @RequestMapping("/test") public Map<Object,Object> test() { return userService.test("張三"); } @RequestMapping("/testObj") public User testObj() { return userService.testObj(new User()); } @RequestMapping("/testNacosDynamicProp") public String testNacosDynamicProp() { return userService.testNacosDynamicProp(); } }
創(chuàng)建負載均衡配置類ConfigBean
package com.consumer.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * @author: yhl * @DateTime: 2019/12/9 13:37 * @Description: */ @Configuration public class ConfigBean { /** * 默認按順序輪詢 * @return */ @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
至此洪乍,我們的模塊都創(chuàng)建完畢了眯杏,接下來進行測試。
-
服務和負載均衡測試
我們將三個模塊的服務都啟動壳澳,如下圖:
利用http接口測試工具來測試我們的接口
選擇一個接口進行測試岂贩,如 http://localhost:8080/test
發(fā)送兩次請求,會發(fā)現打印的請求地址的端口號不同巷波,說明實現了負載均衡萎津。
連續(xù)發(fā)送多次請求,端口號會交替變化抹镊,因為默認的負載均衡策略為輪訓法锉屈。由于本片內容過程長,關于feign的負載均衡垮耳,單獨再開一篇blog颈渊,感興趣的話可以接著看
有什么問題歡迎大家交流。