了解
首先,Spring Cloud Alibaba使用的是Nacos作为服务注册和服务发现的中间件。
能力在提供者那里,而消费者只需知道提供者提供哪些服务,而无需关心提供者在哪里,实际调用过程如下图
准备工作
1、需要下载并安装Nacos最新版
下载安装过程略,如果是单机启动请建立一个批处理放在解压后的bin目录里,命令内容就一行:startup.cmd -m standalone
用单机模式启动Nacos,如果你是Linux系统,请改成.sh并加上bash头
2、启动nacos,默认用户名密码均为nacos,端口号为8848,但同时要注意,如果你是docker部署,因为有gRPC协议,还需要放行9848端口。
3、Nacos作为一个配置中心,还需要加上我们应用的配置,可以少写很多配置。
配置中心添加配置文件
点击加号,添加这三个配置文件,配置格式都为YAML
application-dev.yml内容:
feign:
sentinel:
enabled: true
okhttp:
enabled: true
httpclient:
enabled: false
client:
config:
default:
connectTimeout: 10000
readTimeout: 10000
compression:
request:
enabled: true
response:
enabled: true
management:
endpoints:
web:
exposure:
include: '*'
provider-dev.yml和consumer-dev.yml内容:
spring:
项目搭建
先随便建立一个空白Maven项目,只要pom.xml文件,src目录是不需要的。然后把pom.xml改成如下:
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>provider</module>
<module>consumer</module>
<module>api</module>
</modules>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.1.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2022.0.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2022.0.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.demo</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.demo</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.demo</groupId>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<packaging>pom</packaging>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<version>3.1.4</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
然后搭建三个子项目,api、provider、consumer,分别代表API库、提供者和消费者
目录结构应当是,api、provider、consumer目录和pom.xml文件平级
提供者编写
提供者的pom.xml,在provider目录下。要注意和主项目的dependencyManagement中provider的声明保持一致。
<?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.demo</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider</name>
<dependencies>
</dependencies>
</project>
编写启动类,关键点是添加@EnableFeignClients(basePackages = "com.demo")
注解
package com.demo.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients(basePackages = "com.demo")
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
随便写一个非常正常、平平无奇的Controller:
package com.demo.provider;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
public class ProviderController {
@RequestMapping("sayHello")
public String sayHello(String name){
return "你好,"+name;
}
}
然后在resources目录里建立一个bootstrap.yml文件
server:
port: 9001
spring:
application:
name: provider
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yml
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
注意,把localhost替换成你的Nacos服务器地址
API编写
API的pom.xml如下(除了name和artifactId不一样,其他都和提供者一样)。
<?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.demo</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>api</name>
<dependencies>
</dependencies>
</project>
关键位置来了,API类是这么写的,这里用了OpenFeign技术
package com.demo.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(contextId = "providerMicroService", value = "provider", fallbackFactory = ProviderMicroServiceFallBackFactory.class)
public interface ProviderMicroService
{
@GetMapping("/sayHello")
String sayHello(@RequestParam("name") String name);
}
这里contextId
指的是上下文ID,类名的小写驼峰即可。value
表示你要调哪个服务,fallbackFactory
是指当服务无法访问或抛出异常时服务降级类是哪个。剩下的都很好理解,注意Get Mapping指的就是上面提供者Controller的类和方法的RequestMapping注解拼起来的地址。然后每一个参数都要加上@RequestParam注解并写上叫什么名(不加就会报错)。
然后我们写服务降级类,如果你不想降级,也可以不写:
package com.demo.api;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
@Component
public class ProviderMicroServiceFallBackFactory implements FallbackFactory<ProviderMicroService>
{
@Override
public ProviderMicroService create(Throwable throwable){
return new ProviderMicroService() {
@Override
public String sayHello(String name) {
return "服务访问失败";
}
};
}
}
消费者编写
consumer项目的pom.xml如下,注意这里多了一个对api的引用。
<?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.demo</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer</name>
<dependencies>
<dependency>
<groupId>com.demo</groupId>
<artifactId>api</artifactId>
</dependency>
</dependencies>
</project>
然后编写启动类,同样,关键是@EnableFeignClients(basePackages = "com.demo")
这一行
package com.demo.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients(basePackages = "com.demo")
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
最后我们编写消费者的Controller,这里的重点是MicroService是要用@Resource
引入,不建议使用@Autowired:
package com.demo.consumer;
import com.demo.api.ProviderMicroService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
public class ConsumerController {
@Resource
ProviderMicroService providerMicroService;
@RequestMapping("consumer")
public String consumer(String name){
return providerMicroService.sayHello(name);
}
}
我们编写一个bootstrap.yml文件,用来启动时连接到nacos,只有name和port和provider不一样,其余的配置都是通过配置中心从nacos拉consumer-dev.yml来整合的。
server:
port: 9000
spring:
application:
name: consumer
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
file-extension: yml
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
最后一步:测试
此时我们打开consumer的Controller地址,给一个name参数,即可看到效果。这说明服务已经正常运行。
然后在nacos里可以看到服务的状态,说明微服务架构运行正常: