⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qq_21790633/article/details/105182750 「君宝逍遥」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

本文主要介绍SpringCloud中调用服务的方式:

  • Spring DiscoveryClient
  • 支持 Ribbon 的 RestTemplate
  • Feign客户端

服务测试环境

测试中,发现Netflix的Eureka服务层采用。

主要步骤如下:

1.引入Eureka所需的依赖

<!--eureka服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!--客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

2.修改配置文件

服务端:

eureka:
instance:
hostname: eureka9001.com #eureka服务端的实例名称
instance-id: eureka9001
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false # #false 表示自己就是注册中心,职责就是维护服务实例,并不需要去检索服务
service-url:
defaulteZone: http://127.0.0.1:9001

客户端1:

server:
port: 8002
spring:
application:
name: licensingservice
eureka:
instance:
instance-id: licensing-service-8002
prefer-ip-address: true
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://127.0.0.1:9001/eureka/,

客户端2:

server:
port: 8002
spring:
application:
name: licensingservice
eureka:
instance:
instance-id: licensing-service-8002
prefer-ip-address: true
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://127.0.0.1:9001/eureka/,

一组微服务的不同实例采办服务名称不同,不同的实例ID不同,不同,spring.application.nameeureka.instance.instance-id

3.启动服务

服务端:

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerPort9001_App {
public static void main(String[] args) {
SpringApplication.run(EurekaServerPort9001_App.class,args);
}
}

客户端:

@SpringBootApplication
@RefreshScope
@EnableEurekaClient
public class LicenseApplication_8002 {
public static void main(String[] args) {
SpringApplication.run(LicenseApplication_8002.class, args);
}
}

4.测试

进入到Eureka服务端地址,我这是127.0.0.1:9001,可以查看注册到注册中心的服务。

标签:

注意:Eureka通过两次服务检测均到通过,服务将在间隔10秒内成功启动服务注册等待30秒。

消费者

1.发现客户端方式

服务中既是服务是微信也可以是调用者,消费者配置和上面配置的大体参考一致,依赖及配置服务端启动方式EnableEurekaClient:监听启动。

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class ConsumerApplication_7002 {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication_7002.class, args);
}
}

核心配置类:

@Component
public class ConsumerDiscoveryClient {

@Autowired
private DiscoveryClient discoveryClient;

public ServiceInstance getServiceInstance() {
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("licensingservice");
if (serviceInstances.size() == 0) {
return null;
}
return serviceInstances.get(0);
}

public String getUrl(String url) {
ServiceInstance serviceInstance=this.getServiceInstance();
if (serviceInstance==null)
throw new RuntimeException("404 ,NOT FOUND");
String urlR=String.format(url,serviceInstance.getUri().toString());
return urlR;
}
}

通过DiscoveryClient从尤里卡中获取licensingservice服务的实例,并返回第一个实例。

测试控制器

@RestController
@RequestMapping("test")
public class TestController {
//注意必须new,否则会被ribbon拦截器拦截,改变URL行为
private RestTemplate restTemplate=new RestTemplate();
@Autowired
private ConsumerDiscoveryClient consumerDiscoveryClient;
@RequestMapping("/getAllEmp")
public List<Emp> getAllLicense(){
String url=consumerDiscoveryClient.getUrl("%s/test/getAllEmp");
return restTemplate.getForObject(url,List.class);
}
}

测试:

  1. 调试信息

从该图可以看到licensingservice,拥有两个服务实例,并可以查看实例信息。

  1. 页面返回信息

成功查询到数据库存储信息。

2.Ribbon方式功能的Spring RestTemplate

同上。

核心配置类:

//指明负载均衡算法
@Bean
public IRule iRule() {
return new RoundRobinRule();
}

@Bean
@LoadBalanced //告诉Spring创建一个支持Ribbon负载均衡的RestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}

设置均衡方式为轮询方式。

测试类:

@RestController
@RequestMapping("rest")
public class ConsumerRestController {

@Autowired
private RestTemplate restTemplate;
private final static String SERVICE_URL_PREFIX = "http://LICENSINGSERVICE";

@RequestMapping("/getById")
public Emp getById(Long id) {
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
paramMap.add("id", id);
return restTemplate.postForObject(SERVICE_URL_PREFIX + "/test/getById", paramMap, Emp.class);
}
}

测试结果:

  • 第一次:

  • 第二次:

  • 第三次:

因为采用轮询平均方式分别使用不同的服务实例,未区别,将名称确定了一定的。

这上面,Ribbon 是对第一种方式的封装方式和不同的负载率。 Feign的方式则大大降低了开发客户端和提升速度。

3.feign客户端方式

引入依赖:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

主要代码:

@FeignClient(value = "LICENSINGSERVICE",fallbackFactory = ServiceImp.class)
public interface ServiceInterface {

@RequestMapping("/test/getById")
Emp getById(@RequestParam("id") Long id);

@RequestMapping("/test/getLicenseById")
License getLicenseById(@RequestParam("id") Long id);

@RequestMapping("/test/getAllEmp")
List<Emp> getAllLicense();
}
@Component
public class ServiceImp implements FallbackFactory<ServiceInterface> {

@Override
public ServiceInterface create(Throwable throwable) {
return new ServiceInterface() {
@Override
public Emp getById(Long id) {
Emp emp = new Emp();
emp.setName("i am feign fallback create");
return emp;
}

@Override
public License getLicenseById(Long id) {
return null;
}

@Override
public List<Emp> getAllLicense() {
return null;
}
};
}
}

注采用接口模式,通过指定服务名以及方法,在服务开发结果不佳时,方便返回默认的,而不是一个不友好的错误。

主启动类:

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Consumer_feign_Application_7004 {
public static void main(String[] args) {
SpringApplication.run(Consumer_feign_Application_7004.class, args);
}
}

测试类:

@RestController
@RequestMapping("rest")
public class ConsumerRestController {
@Autowired
private ServiceInterface serviceInterface;

@Autowired
private RestTemplate restTemplate;
@RequestMapping("/getById")
public Emp getById(Long id) {
return serviceInterface.getById(id);
}
}

测试结果:

  • 正常测试:

  • 关闭两个实例,模拟服务实例死亡:

假装能够故障服务调用,也可以实现调用的服务时,友好的信息。

以此方式,由低上,从不同层次实现了SpringCloud中的微服务相互引用。

文章目录
  1. 1. 服务测试环境
    1. 1.1. 1.引入Eureka所需的依赖
    2. 1.2. 2.修改配置文件
    3. 1.3. 3.启动服务
    4. 1.4. 4.测试
  2. 2. 消费者
    1. 2.1. 1.发现客户端方式
    2. 2.2. 2.Ribbon方式功能的Spring RestTemplate
    3. 2.3. 3.feign客户端方式