微服务框架之 springcloud 是最流行的,加上 springboot,很容易快速上手。spring cloud 有很多组件,比如 注册中心 eureka、负载均衡 ribbon、网关zuul、feign客户端、容错组件 Hystrix 等等。还有 RestTemplate 可以很容易的发起 restful api调用。由于 组件较多、并且 名字 看起来、写起来、读起来 都有点 不友好,就会觉得 学习 spring cloud 是不是很难?实际上,spring boot 做了完整的封装,对于使用者来说,基本上就是:1、引入 pom依赖jar 2、使用简单的注解 就能够玩起来了。对于其中的细节,还是需要研究一番,不然上线容易出问题。
1. 注册中心
单独起一个 spring boot 服务
pom.xml
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wxj</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<!-- Spring Cloud -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.application.name=eureka-server
server.port=8761
# 由于该应用为注册中心,所以设置为false,代表不向注册中心注册自己
#一定要配置为false,不然启动时会把自己当作客户端向自己注册,会报错
eureka.client.register-with-eureka=false
# 由于注册中心的职责就是维护服务实例,它并不需要去检索服务,所以也设置为 false
eureka.client.fetch-registry=false
应用启动类加注解:
@EnableEurekaServer // 开启eureka 服务
启动应用,一个 eureka 注册中心 就OK了。
2. 网关
单独起一个 spring boot 服务
pom.xml
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wxj</groupId>
<artifactId>gateway-zuul</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway-zuul</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!-- 微服务的注册与发现 -->
<!-- eureka 客户端依赖包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--zuul 网关 ,自动完成 负载均衡-->
<!-- 说明在默认情况下,Zuul会代理所有注册到Eureka Server的微服务,并且Zuul的路由规则如下:
http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**会被转发到serviceId
对应的微服务-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
<!-- Spring Cloud -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.application.name=gateway-zuul-service
server.port=9083
#将 zuul 注册到 eureka
#Eureka服务的地址,在启动的时候需要将自身的信息注册到Eureka中去
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
# 采用IP注册
eureka.instance.preferIpAddress=true
# 定义实例ID格式
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
应用启动类加注解:
@EnableZuulProxy
启动应用,网关服务就OK了。
3. 服务应用
单独起一个 springboot 服务
pom.xml
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wxj</groupId>
<artifactId>user-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>compile</scope>
</dependency>
</dependencies>
<!-- Spring Cloud -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
spring.application.name=user-service
server.port=8081
#Eureka服务的地址,在启动的时候需要将自身的信息注册到Eureka中去
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
# 采用IP注册
eureka.instance.preferIpAddress=true
# 定义实例ID格式
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
接口服务,自己定义一个。
启动服务
4. 消费者服务
单独起一个 spring boot 服务,以下代码都是在消费者端写的
pom.xml
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wxj</groupId>
<artifactId>article-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>article-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!-- 微服务的注册与发现 -->
<!-- eureka 客户端依赖包 start-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- eureka 客户端依赖包 end-->
<!-- 客户端侧 的负载均衡 -->
<!-- ribbon相关包 被 eureka自动引入了 -->
<!-- ribbon 依赖包 start-->
<!-- <dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-core</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-loadbalancer</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava</artifactId>
<version>1.0.10</version>
</dependency>-->
<!-- ribbon 依赖包 end-->
<!-- spring cloud 继承 ribbon-->
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>-->
<!-- feign 声明式的API调用 ,不用 RestTemplate 拼接 URL-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--Hystrix 容错 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- Hystrix Dashboard可视化监控数据-->
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>-->
</dependencies>
<!-- Spring Cloud -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
消费者发起调用的核心代码:
4.1 RestTemplate 直接调用
@Bean(name = "restTemplate")
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
/**
* 直接通过 url 调用服务
*/
@Autowired
@Qualifier("restTemplate")
private RestTemplate restTemplate;
@GetMapping("/article/callHello")
public String callHello() {
return restTemplate.getForObject("http://localhost:8081/user/hello", String.class);
}
4.2 RestTemplate 通过服务名 负载均衡调用
@Bean(name = "loadbalanceRestTemplate")
@LoadBalanced // 加上这个注解,就走的是 注册中心获取服务地址, 并且实现了 复制均衡
public RestTemplate getRestTemplate2() {
return new RestTemplate();
}
/**
* 通过 服务名 到 注册中心 获取服务 调用
*/
@Autowired
@Qualifier("loadbalanceRestTemplate")
private RestTemplate loadbalanceRestTemplate;
@GetMapping("/article/callHello2")
public String callHello2() {
return loadbalanceRestTemplate.getForObject("http://user-service/user/hello", String.class);
}
4.3 feign 发起调用
消费端 定义一个feign客户端,代表 服务端提供的 服务
/**
* 开启 feign 客户端,可指定服务端的 服务名,和注册中心保持一直
*/
@FeignClient(name = "user-service")
public interface ProviderFeignProxyClient {
/**
*
* 服务端 提供的 服务 restful API
* @param name
* @return
*/
@GetMapping("/house/data")
HouseInfo hello(@RequestParam("name") String name);
}
使用feign客户端发起调用:
/**
* 在 启动类 加上 @EnableFeignClients 注解
*
* 在 消费者中 注入 feign client,即可。
*
* 可以 不用 RestTemplate 就能完成 调用了
*/
@Autowired
ProviderFeignProxyClient providerFeignProxyClient;
@GetMapping("/feigntest")
public HouseInfo feignTest(@RequestParam("name") String name){
return providerFeignProxyClient.hello(name);
}
4.4 开启 hystrix 功能
只要加上 @HystrixCommand 注解就行了
@HystrixCommand(
// 设置 容错 方法
fallbackMethod = "defaultInfo")
@GetMapping("/hystrixTest")
public HouseInfo hystrixTest(@RequestParam("name") String name){
System.out.printf("hystrixTest");
return providerFeignProxyClient.hello(name);
}
public HouseInfo defaultInfo(String name){
return new HouseInfo(1L,"默认地址");
}
总结:
以上就是 spring cloud 入门示例,通过这个示例 可以 很好的 感受 spring cloud 提供的 微服务能力。这只是 入门,会用,想要提高,还需要 研究其实现原理。