【详细】手把手教你搭建Spring Cloud项目

本文详细介绍如何使用Spring Boot和Spring Cloud构建微服务架构,包括搭建Eureka服务中心、微服务工程、基于Ribbon的客户端、熔断器Hystrix、Feign整合以及网关Gateway的使用。
摘要由CSDN通过智能技术生成

参考1

一、搭建eureka服务中心

要注意cloud版本和boot版本的对应关系,否则服务都启动不了
本项目使用版本如下:
spring-boot :2.3.1.RELEASE spring-cloud:Hoxton.SR7

构建springBoot项目,引入eureka服务的依赖

这里只需要引入这一个就ok
在这里插入图片描述

配置application文件

采用yml配置一定要注意格式;
defaultZone 后端口后尽量别在加,可能导致404(因为这个坑搞了好久)

# 指定服务名称
spring:
  application:
    name: eureka1

# 端口自定义
server:
  port: 8752

# 指定当前eureka客户端的注册地址,也就是eureka服务的提供方,当前配置的服务的注册服务方
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false #不把自己(eureka-server)注册到eureka上(不做高可用的情况下)
    fetch-registry: false  #不从eureka上来获取服务的注册信息(因为本身就是注册中心,消费者就需要获取提供者的信息)
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}  # 后边再加一层(如/eureka)刚问时会404
启动类上添加@EnableEurekaServer

添加@EnableEurekaServer,表明标注类是一个Eureka Server

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaApplication.class, args);
	}

}

在这里插入图片描述

访问eureka注册中心管理面

在这里插入图片描述

二、搭建一个springboot微服务工程,用于提供服务

搭建SpringBootService,这里是各个微服务的业务逻辑,将其注册到注册中心去,其作为服务提供者,也就是服务端
spring-boot :2.3.1.RELEASE spring-cloud:Hoxton.SR7

pom.xml
<dependencies>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <!-- eureka-client -->
   <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
   </dependency>
</dependencies>
<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>
   </dependencies>
</dependencyManagement>

启动类上添加@EnableDiscoveryClient注解

也可以使用@EnableEurekaClient,添加后就会被EurekaService扫描到,注册到注册中心

@SpringBootApplication
@EnableDiscoveryClient // @EnableEurekaClient只适用于Eureka作为注册中心;@EnableDiscoveryClient 可以是其他注册中心
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
配置application.yml

TransportException: Cannot execute request on any known server

server:
  port: 8760
# eureka-client 
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8752/eureka  # 服务地址/eureka (/eureka一定要加,否则启动直接报错TransportException: Cannot execute request on any known server)

# application-name
spring:
  application:
    name: ServiceProvider1
启动微服务

注意,要先启动注册服务,否则启动微服务时会报错RedirectingEurekaHttpClient : Request execution error…
在这里插入图片描述
从控制台打印日志可以看到,注册中心发现并已注册微服务SpringBootService1:8760

再次查看注册中心

可以看到,SpringBootService1确实已被注册管理
在这里插入图片描述

微服务也可以正常访问

http://localhost:8760/users/query/all
我这里boot用的我之前练习的项目,所以直接能从数据库中获取到数据
在这里插入图片描述
但是我们一般不直接调用所需的微服务(服务提供者),而是经过注册中心获取所需的服务提供者列表(为一个列表,此列表包含了能提供相应服务的服务器),他们也许是个集群,因此server会返回一个 ip+端口号的表,服务消费者通过相应算法访问这表上的不同服务器,这些服务器提供的是相同的服务,这种在服务消费者一方挑选服务器为自己服务的方式是一种客户端的负载均衡。在cloud中ribbon就是一种负载均衡的客户端

三、搭建基于ribbon的客户端,用于消费服务

同二搭建boot微服务工程,引入相关的依赖(复制一份上个工程代码,修改下即可)

pom.xml

在上个pom上新增ribobon依赖即可

<!-- ribbon -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>  
application.xml
server:
  port: 8770
# eureka-client
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8752/eureka  # 服务地址/eureka (/eureka一定要加,否则启动直接报错TransportException: Cannot execute request on any known server)

# application-name
spring:
  application:
    name: ServiceConsumer1
定义启动类
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}
定义controller类来编写ribbon的代码

其实在这之前和服务提供类一样,这一步是关键,我们需要使用restTemplate+ribbon 来访问服务提供者
这里我们使用自动注入并直接调用restTemplate对象的方式来调用服务提供者,以达到微服务之间的通信;
首先,需要定义一个@Bean来产生一个restTemplate Bean对象,交给Spring容器管理
添加@LoadBalanced后才能让RestTemplate具有负载均衡的能力

@Configuration
public class Beans {

	@Bean // @Bean是放在方法的注释,它很明确地告诉被注释的方法,你给我产生一个Bean,然后交给Spring容器
	@LoadBalanced // 实现负载匀衡; 使用restTemplate时就可以直接使用服务名访问
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}
}

接着我们就来写下控制层的代码

@RestController
@RequestMapping("/consumer")
public class ConsumerController {

	@Autowired
	private LoadBalancerClient loadBalancerClient;
	@Autowired
	private RestTemplate restTemplate;

	@RequestMapping("/hello")
	public String hello() {
		// 方式1:根据服务名 获取服务列表 根据算法选取某个服务 并访问某个服务的网络位置
		ServiceInstance serviceProvider = loadBalancerClient.choose("ServiceProvider1");
		String url = "http://" + serviceProvider.getHost() + ":" + serviceProvider.getPort() +
				"/users/query/all";
		String response = new RestTemplate().getForObject(url, String.class);
		return response + "\t" + url;

		// 方式2:可以直接使用服务名访问
//		return restTemplate.getForObject("http://ServiceProvider1/users/query/all", String.class);
	}
}
启动测试

依次启动注册中心,服务提供者、服务消费者三个服务
在这里插入图片描述
我们通过注册中心可以看到,2个微服务都被成功注册
在这里插入图片描述
浏览器访问服务消费方rest接口,可以看到成功从服务提供端获取了数据,因为只有一个服务端节点,所以ribbon只会将请求转发到8760端口的节点
在这里插入图片描述
看到这里,大伙可能有个疑问上边只有一个单节点服务提供者(端口8760),每次访问的都是这一个节点,这怎么能体现负载均衡呢?别急,我们接着就来构造下整个微服务的多实例来再看看

四、构建多实例的服务提供者

参考方法2

构建ServiceProvider1多实例

端口:8061
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
到此处,我们就构造好了一个ServiceProvider1服务的1个实例,端口为8061

启动项目,查看注册中心

在这里插入图片描述
在这里插入图片描述
我们可以看到,8061的节点已被注册,那接下来我们来测试下负载均衡

负载均衡测试

在这里插入图片描述
在这里插入图片描述
可以看到,通过消费端访问服务端时,连续请求时,ribbon负载均衡策略默认是轮询,也就是会将请求循环转发给每一个可用的服务

在微服务架构中多层服务之间会相互调用(就像消费端调用服务端),如果其中有一层服务故障了,可能会导致一层服务或者多层服务故障,从而导致整个系统故障。这种现象被称为服务雪崩效应, 熔断就是服务雪崩的一种有效解决方案。当指定时间窗内的请求失败率达到设定阈值时,系统将通过断路器直接将此请求链路断开,接下来我们来看看

五、使用熔断器Hystrix

Hystrix熔断器可以是服务端也可以是客户端(消费端)的,而服务端的熔断器我们一般通过整合Feign实现,这个后边再说
Hystrix使用说明,参数配置
熔断器可视化界面hystrix dashboard

客户端熔断器

pom中新增依赖
注意导包时spring-cloud-starter-netflix-hystrix,不是spring-cloud-starter-hystrix否则可能会找不到某些注解

<!-- hystrix -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

修改启动类,添加注解@EnableHystrix 开启Hystrix的熔断器功能

@SpringBootApplication
@EnableDiscoveryClient // @EnableEurekaClient只适用于Eureka作为注册中心;@EnableDiscoveryClient 可以是其他注册中心
@EnableHystrix // 开启Hystrix的熔断器功能
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

修改下controller代码,我们让客户端请求服务端时,如果超时100ms,则直接回调fallbackMethod,而不会一致阻塞,占用线程资源

@RestController
@RequestMapping("/consumer")
public class ConsumerController {

	@Autowired
	private LoadBalancerClient loadBalancerClient;
	@Autowired
	private RestTemplate restTemplate;

	private static String urlMsg = null;

	@HystrixCommand(commandProperties = {
			// 设置单线程请求的超时时间,如果超时,回调方法,而不会一直阻塞
			@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="100")
	}, fallbackMethod = "fallBackHello")
	@RequestMapping("/hello")
	public String hello() {
		// 方式1:根据服务名 获取服务列表 根据算法选取某个服务 并访问某个服务的网络位置
		ServiceInstance serviceProvider = loadBalancerClient.choose("ServiceProvider1");
		String url = "http://" + serviceProvider.getHost() + ":" + serviceProvider.getPort() +
				"/users/query/all";
		urlMsg = url;
		String response = new RestTemplate().getForObject(url, String.class);
		return response + "\t" + url;

		// 方式2:可以直接使用服务名访问
//		return restTemplate.getForObject("http://ServiceProvider1/users/query/all", String.class);
	}

	// 熔断策略的回调方法
	public String fallBackHello() {
		return urlMsg + " 当前请求人数较多,请稍后再试...";
	}
}
熔断测试

依次启动4个服务,使用http://localhost:8770/consumer/hello 访问时,可以正常访问到服务端8760和8061 2个节点
这时候,如果我们把8760服务停掉,再来看下
当ribbon转发请求到8760节点时,因为服务故障,所以调用该服务的请求快速失败,而不是线程等待。
在这里插入图片描述
而对于转发到8061节点的请求则正常返回
在这里插入图片描述
这时候我们再启动8760的服务,又可以正常访问了
在这里插入图片描述

六、整合Feign

在上边我们搭建Ribbon的时候,消费端是通过RestTemplate去调用服务端的一个接口的,如果调用每一个接口都采用这种方式,这种模板代码看起来很臃肿,为了消除这种弊端,往往在微服务间的调用我们采用Feign注解的方式映射到对应到请求地址,这样就像我们平时调用自己写的方法一样容易,它让微服务之间的调用变得更简单了,类似controller调用service
而Feign整合后,也可以作为负载均衡和熔断器使用,不必再引入Ribbon和Hystrix的依赖
接下来,我们就在服务端的调用之间来引入feign来简单实现下…
在这之前,同二我们再创建一个ServiceProvider2

pom.xml

ServiceProvider1新增fegin依赖

<!-- feign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
修改ServiceProvider1启动类

ServiceProvider1启动类上新增@EnableFeignClients注解

@SpringBootApplication
@EnableDiscoveryClient // @EnableEurekaClient只适用于Eureka作为注册中心;@EnableDiscoveryClient 可以是其他注册中心
@EnableFeignClients // 启用feign客户端
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}
ServiceProvider1 定义Feign API

接口中映射具体请求的服务以及请求绝对路径

@FeignClient(name = "ServiceProvider2") // 被调用服务(service2)yml中定义的application.name
public interface ServiceAToBFeignApi {
	@GetMapping("/service2/hello") // 具体的请求路径
	String getHelloService2();
}
ServiceProvider1定义controller类

注入Feign API,直接调用接口即可

@RestController
@RequestMapping("/service1")
public class ServiceAToBController {
	@Autowired
	private ServiceAToBFeignApi serviceAToBFeignApi;
	@GetMapping("/hello")
	public String helloService1() {
		return serviceAToBFeignApi.getHelloService2();
	}
}
修改ServiceConsumer1的controller代码

只需要将之前代码中url改变部分为/service1/hello,ribbon还使用的是restTemplate去请求(当然我们也可以使用feign去代替)

@RequestMapping("/hello")
	public String hello() {
		// 方式1:根据服务名 获取服务列表 根据算法选取某个服务 并访问某个服务的网络位置
		ServiceInstance serviceProvider = loadBalancerClient.choose("ServiceProvider1");
		String url = "http://" + serviceProvider.getHost() + ":" + serviceProvider.getPort() +
				"/service1/hello";
		urlMsg = url;
		String response = new RestTemplate().getForObject(url, String.class);
		return url + "\t" + response;

		// 方式2:可以直接使用服务名访问
//		return restTemplate.getForObject("http://ServiceProvider1/users/query/all", String.class);
	}
ServiceProvider2定义controller类
@RestController
@RequestMapping("/service2")
public class HelloController {

    @GetMapping("/hello")
    public String helloService2(){
        return "service1调用service2";
    }
}
启动测试

依次来启动服务,查看注册中心,可以看到新增的ServiceProvider2已经注册
在这里插入图片描述

直接通过ribbon消费者端来访问,成功获取到ServiceProvider2的返回结果
http://localhost:8770/consumer/hello
在这里插入图片描述

七、网关gateway

当我们的整个cloud构架中微服务越来越多的时候,我们就需要使用网关来作为统一入口,它会对前端的每个请求做识别过滤,然后再动态的将请求路由到不同的后端集群中

持续更新中…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值