一個實例,輕松演示Spring Cloud集成Nacos實例
前言
學(xué)習(xí)一個技術(shù)框架,最快速的手段就是將其集成到項目中,體驗一下它的功能。在這個過程中,你還踩到很多坑。而排坑的過程,又是一次能力的提升。
前面我們寫了一些列Nacos的文章,經(jīng)過《學(xué)習(xí)Nacos?咱先把服務(wù)搞起來,實戰(zhàn)教程》的介紹,我們已經(jīng)可以把Nacos Server給啟動起來了。
這篇文章,我們就來學(xué)習(xí)一下如何將Nacos集成到Spring Cloud項目中,同時實例演示一下,基于Nacos的微服務(wù)之間的兩種調(diào)用形式。
集成與版本
為了演示這個案例,大家首先要將Nacos Server跑起來。同時會構(gòu)建兩個微服務(wù):服務(wù)提供方(Provider)和服務(wù)消費方(Consumer)。然后,通過兩個服務(wù)之間的調(diào)用及配合查看Nacos Server中的注冊信息來進(jìn)行驗證。
我們知道,Nacos隸屬于Spring Cloud Alibaba系列中的組件。所以,在進(jìn)行集成之前,有一件事一定要注意,那就是要確保Spring Cloud、Spring Boot、Spring Cloud Alibaba版本的一致。不然發(fā)生一些莫名其妙的異常。
關(guān)于版本信息可以在https://spring.io/projects/spring-cloud中進(jìn)行查看。
這里采用Spring Boot的版本為2.4.2,Spring Cloud采用2020.0.0、Spring Cloud Alibaba采用2021.1。如你采用其他版本,一定確保對照關(guān)系。
Nacos服務(wù)提供者
依賴配置
創(chuàng)建項目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>
然后添加依賴:
<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為服務(wù)發(fā)現(xiàn)的依賴包。
配置文件
提供者添加配置(application.yml)
server:
port: 8081
spring:
application:
name: user-service-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
其中Nacos Server的地址和端口號默認(rèn)是127.0.0.1:8848。name用來指定此服務(wù)的名稱,消費者可通過注冊的這個名稱來進(jìn)行請求。
業(yè)務(wù)代碼
在編寫業(yè)務(wù)代碼之前,我們先來看一下提供者的啟動類:
// 版本不同,低版本需要明確使用@EnableDiscoveryClient注解
//@EnableDiscoveryClient
@SpringBootApplication
public class NacosProviderApplication {
public static void main(String[] args) {
SpringApplication.run(NacosProviderApplication.class, args);
}
}
注意上面的注釋部分,此版本已經(jīng)不需要@EnableDiscoveryClient注解了,而較低的版本需要添加對應(yīng)的注解。
下面新建一個UserController服務(wù):
@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
}
然后啟動服務(wù),查看Nacos Server,會發(fā)現(xiàn)已經(jīng)成功注冊。
Nacos服務(wù)消費者
消費者的創(chuàng)建與提供者基本一致,唯一不同的是調(diào)用相關(guān)的功能。
創(chuàng)建項目
創(chuàng)建Spring Boot項目spring-cloud-alibaba-nacos-consumer1,pom中的依賴與提供者基本一致,但還需要在它的基礎(chǔ)上增加兩個依賴:
<!-- consumer需要額外添加負(fù)載均衡的依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<!-- 基于Feign框架進(jìn)行調(diào)用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
其中l(wèi)oadbalancer是用來做服務(wù)調(diào)用負(fù)載均衡的,如果不添加此依賴,在調(diào)用的過程中會出現(xiàn)如下一次:
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是用來實現(xiàn)基于feign框架的微服務(wù)調(diào)用,也就是讓服務(wù)之間的調(diào)用更加方便。這個框架是可選的,如果你想基于RestTemplate方式進(jìn)行調(diào)用,則不需要此框架的依賴。
配置文件
消費者添加配置(application.yml):
spring:
application:
name: user-service-consumer
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
# 消費者將要去訪問的微服務(wù)名稱(注冊成功進(jìn)nacos的微服務(wù)提供者)
service-url:
nacos-user-service: http://user-service-provider
同樣server-addr指定注冊Nacos Server的地址和端口。而配置中定義的service-url中便用到了服務(wù)提供者的服務(wù)名稱user-service-provider。
業(yè)務(wù)代碼
關(guān)于啟動類上的注解,與提供者一樣,如果根據(jù)使用的版本決定是否使用@EnableDiscoveryClient注解。
創(chuàng)建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框架的模式進(jìn)行請求的。
先來看基于RestTemplate方式的配置,需要先來實例化一下RestTemplate:
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
注意,這里使用了@LoadBalanced注解,RestTemplateCustomizer會給標(biāo)有@LoadBalance的RestTemplate添加一個攔截器,攔截器的作用就是對請求的URI進(jìn)行轉(zhuǎn)換獲取到具體應(yīng)該請求哪個服務(wù)實例ServiceInstance。如果缺少這個注解,也會報上面提到的異常。
基于Feign的模式對應(yīng)的UserFeignService如下:
@FeignClient(name = "user-service-provider")
public interface UserFeignService {
/**
* 基于Feign的接口調(diào)用
*
* @param userId 用戶ID
* @return UserDetail
*/
@GetMapping(value = "/user/getUserById")
UserDetail getUserById(@RequestParam Integer userId);
}
其中@FeignClient通過name屬性指定調(diào)用微服務(wù)的名稱,下面定義的方法則對應(yīng)提供者的接口。
啟動服務(wù),查看Nacos Server的注冊情況。
結(jié)果驗證
此時,本地分別請求兩個URL地址:
http://localhost:8080/order/getUserInfo
http://localhost:8080/order/getUserInfo1
訪問一下,可以成功的返回結(jié)果:
// getUserInfo對應(yīng)結(jié)果
{
"userId": 1,
"username": "Tom"
}
// getUserInfo1對應(yīng)結(jié)果
{
"userId": 2,
"username": "Other"
}
至此,Spring Cloud集成Nacos實例演示完畢,完整的源代碼地址:https://github.com/secbr/spring-cloud 。
小結(jié)
經(jīng)過上述實例,我們成功的將Nacos集成到了Spring Cloud當(dāng)中。相對來說,整個過程還是比較簡單的,在實踐時,大家唯一需要注意的就是版本問題。Spring Cloud的不同版本,內(nèi)容和用法調(diào)整較大,多參考官方文檔的說明。



