學習一個技術框架,最快速的手段就是將其集成到項目中,體驗一下它的功能。在這個過程當中,你還踩到不少坑。而排坑的過程,又是一次能力的提高。java
前面咱們寫了一些列Nacos的文章,通過《學習Nacos?咱先把服務搞起來,實戰教程》的介紹,咱們已經能夠把Nacos Server給啓動起來了。git
這篇文章,咱們就來學習一下如何將Nacos集成到Spring Cloud項目中,同時實例演示一下,基於Nacos的微服務之間的兩種調用形式。github
爲了演示這個案例,你們首先要將Nacos Server跑起來。同時會構建兩個微服務:服務提供方(Provider)和服務消費方(Consumer)。而後,經過兩個服務之間的調用及配合查看Nacos Server中的註冊信息來進行驗證。web
咱們知道,Nacos隸屬於Spring Cloud Alibaba系列中的組件。因此,在進行集成以前,有一件事必定要注意,那就是要確保Spring Cloud、Spring Boot、Spring Cloud Alibaba版本的一致。否則發生一些莫名其妙的異常。spring
關於版本信息能夠在https://spring.io/projects/sp...app
這裏採用Spring Boot的版本爲2.4.2,Spring Cloud採用2020.0.0、Spring Cloud Alibaba採用2021.1。如你採用其餘版本,必定確保對照關係。負載均衡
建立項目Spring Boot的項目spring-cloud-alibaba-nacos-provider1,在pom文件中添加定義依賴的版本限制:框架
<properties> <java.version>1.8</java.version> <spring-boot.version>2.4.2</spring-boot.version> <spring-cloud.version>2020.0.0</spring-cloud.version> <cloud-alibaba.version>2021.1</cloud-alibaba.version> </properties> <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>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
而後添加依賴:ide
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
其中actuator爲健康檢查依賴包,nacos-discovery爲服務發現的依賴包。spring-boot
提供者添加配置(application.yml)
server: port: 8081 spring: application: name: user-service-provider cloud: nacos: discovery: server-addr: 127.0.0.1:8848
其中Nacos Server的地址和端口號默認是127.0.0.1:8848。name用來指定此服務的名稱,消費者可經過註冊的這個名稱來進行請求。
在編寫業務代碼以前,咱們先來看一下提供者的啓動類:
// 版本不一樣,低版本須要明確使用@EnableDiscoveryClient註解 //@EnableDiscoveryClient @SpringBootApplication public class NacosProviderApplication { public static void main(String[] args) { SpringApplication.run(NacosProviderApplication.class, args); } }
注意上面的註釋部分,此版本已經不須要@EnableDiscoveryClient註解了,而較低的版本須要添加對應的註解。
下面新建一個UserController服務:
@RestController @RequestMapping("/user") public class UserController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @GetMapping("/getUserById") public UserDetail getUserById(Integer userId) { logger.info("查詢用戶信息,userId={}", userId); UserDetail detail = new UserDetail(); if (userId == 1) { detail.setUserId(1); detail.setUsername("Tom"); } else { detail.setUserId(2); detail.setUsername("Other"); } return detail; } }
其中用到的實體類UserDetail爲:
public class UserDetail { private Integer userId; private String username; // 省略getter/setter }
而後啓動服務,查看Nacos Server,會發現已經成功註冊。
消費者的建立與提供者基本一致,惟一不一樣的是調用相關的功能。
建立Spring Boot項目spring-cloud-alibaba-nacos-consumer1,pom中的依賴與提供者基本一致,但還須要在它的基礎上增長兩個依賴:
<!-- consumer須要額外添加負載均衡的依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> </dependency> <!-- 基於Feign框架進行調用--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
其中loadbalancer是用來作服務調用負載均衡的,若是不添加此依賴,在調用的過程當中會出現以下一次:
java.net.UnknownHostException: user-provider at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:196) ~[na:1.8.0_271] at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:394) ~[na:1.8.0_271] at java.net.Socket.connect(Socket.java:606) ~[na:1.8.0_271] at java.net.Socket.connect(Socket.java:555) ~[na:1.8.0_271]
而openfeign是用來實現基於feign框架的微服務調用,也就是讓服務之間的調用更加方便。這個框架是可選的,若是你想基於RestTemplate方式進行調用,則不須要此框架的依賴。
消費者添加配置(application.yml):
spring: application: name: user-service-consumer cloud: nacos: discovery: server-addr: 127.0.0.1:8848 # 消費者將要去訪問的微服務名稱(註冊成功進nacos的微服務提供者) service-url: nacos-user-service: http://user-service-provider
一樣server-addr指定註冊Nacos Server的地址和端口。而配置中定義的service-url中便用到了服務提供者的服務名稱user-service-provider。
關於啓動類上的註解,與提供者同樣,若是根據使用的版本決定是否使用@EnableDiscoveryClient註解。
建立UserController:
@RestController @RequestMapping("/order") public class UserController { @Resource private UserFeignService userFeignService; @Resource private RestTemplate restTemplate; @Value("${service-url.nacos-user-service}") private String userProvider; @GetMapping("getUserInfo") public UserDetail getUserInfo() { int userId = 1; ResponseEntity<UserDetail> result = restTemplate.getForEntity(userProvider + "/user/getUserById?userId=" + userId, UserDetail.class); return result.getBody(); } @GetMapping("getUserInfo1") public UserDetail getUserInfoByFeign() { return userFeignService.getUserById(2); } }
上述代碼中展現了兩種方式的請求,其中注入的RestTemplate和getUserInfo方法是一組,注入的UserFeignService和getUserInfoByFeign方法是一組。前者是基於RestTemplate方式請求,後者是基於Feign框架的模式進行請求的。
先來看基於RestTemplate方式的配置,須要先來實例化一下RestTemplate:
@Configuration public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
注意,這裏使用了@LoadBalanced註解,RestTemplateCustomizer會給標有@LoadBalance的RestTemplate添加一個攔截器,攔截器的做用就是對請求的URI進行轉換獲取到具體應該請求哪一個服務實例ServiceInstance。若是缺乏這個註解,也會報上面提到的異常。
基於Feign的模式對應的UserFeignService以下:
@FeignClient(name = "user-service-provider") public interface UserFeignService { /** * 基於Feign的接口調用 * * @param userId 用戶ID * @return UserDetail */ @GetMapping(value = "/user/getUserById") UserDetail getUserById(@RequestParam Integer userId); }
其中@FeignClient經過name屬性指定調用微服務的名稱,下面定義的方法則對應提供者的接口。
啓動服務,查看Nacos Server的註冊狀況。
此時,本地分別請求兩個URL地址:
http://localhost:8080/order/getUserInfo http://localhost:8080/order/getUserInfo1
訪問一下,能夠成功的返回結果:
// getUserInfo對應結果 { "userId": 1, "username": "Tom" } // getUserInfo1對應結果 { "userId": 2, "username": "Other" }
至此,Spring Cloud集成Nacos實例演示完畢,完整的源代碼地址:https://github.com/secbr/spri... 。
通過上述實例,咱們成功的將Nacos集成到了Spring Cloud當中。相對來講,整個過程仍是比較簡單的,在實踐時,你們惟一須要注意的就是版本問題。Spring Cloud的不一樣版本,內容和用法調整較大,多參考官方文檔的說明。