JAVAEE细细看 框架32 - SpringCloud 微服务(二) 服务治理-Eureka

Eureka介绍

Eureka
• Eureka 是 Netflix 公司开源的一个服务注册与发现的组件 。
• Eureka 和其他 Netflix 公司的服务组件(例如负载均衡、熔断器、网关等) 一起,被 Spring Cloud 社区整合为
Spring-Cloud-Netflix 模块。
• Eureka 包含两个组件:Eureka Server (注册中心) 和 Eureka Client (服务提供者、服务消费者)。

在这里插入图片描述

在这里插入图片描述

1. Eureka快速入门-环境搭建

1、搭建eureka-provider 提供者

2、搭建eureka-consumer消费者

如果导入示例代码启动 报以下错误

在这里插入图片描述

在这里插入图片描述

2. RestTemplate远程调用

声明redisTemplate bean

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

注入RestTemplate 完成调用

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/goods/{id}")
    public Goods findGoodsById(@PathVariable("id") int id){
        System.out.println("findGoodsById..."+id);
        String url = "http://localhost:8000/goods/findOne/"+id;
        // 3. 调用方法
        Goods goods = restTemplate.getForObject(url, Goods.class);
        return goods;
    }
}

扩展1、

底层采用JDK原生的URLConnection(默认的),使用okhttp客户端性能会高一点

<dependency>
	<groupId>com.squareup.okhttp3</groupId>
	<artifactId>okhttp</artifactId>
	<version>3.14.2</version>
</dependency>

代码

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
    }
}

扩展2

RestTemplate其他api用法

被调用方

User

public class User {
    private int id;
    private String username;
    private String password;
    private int age;
    //getter  setter

UserController

package com.ittest.provider.controller;

import com.ittest.provider.domain.User;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/")
public class UserController {
    @GetMapping("/user/{id}")
    public User queryById(@PathVariable Long id, String name){
        System.out.println(id+"----"+name);
        User user = new User();
            user.setId(1);
            user.setUsername("zhangsan");
            user.setPassword("123456");
            user.setAge(11);
        return user;
    }
    @PostMapping("/user/add")
    public User add(@RequestBody User user){
        System.out.println(user);
        return user;
    }
    @PostMapping("/user/add2")
    public User add2(User user){
        System.out.println(user);
        return user;
    }
}

调用方

UserRestTemplateTestController

package com.ittest.consumer.controller;

import com.ittest.consumer.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/")
public class UserRestTemplateTestController {

    @Autowired
    RestTemplate restTemplate;


    @RequestMapping("/testGet")
    public void test(){
        String url = "http://localhost:8000/user/1";
        //restTemplate可以对json格式字符串进行反序列化
        User user = restTemplate.getForObject(url, User.class);
        System.out.println("user:"+user);

        ResponseEntity<Map> forEntity = restTemplate.getForEntity(url, Map.class);
        Map map = forEntity.getBody();
        System.out.println("forEntity:"+map);

        ResponseEntity<User> get = restTemplate.exchange(url+"?name=lisi", HttpMethod.GET, null, User.class);
        System.out.println("get exchange:"+ get.getBody());
    }
    //提交json数据
    @RequestMapping("/testPostJsonData")
    public void testPostJsonData(){
        String addUrl = "http://localhost:8000/user/add";

        User user = new User();
        user.setUsername("王五");
        user.setAge(1);
        user.setPassword("wangwu");
        ResponseEntity<Map> postForEntity = restTemplate.postForEntity(addUrl, user, Map.class);
        Map forEntityBody = postForEntity.getBody();
        System.out.println("postForEntity:"+forEntityBody);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        Map bodyMap = new HashMap();
        bodyMap.put("userName","zhangsan");
        bodyMap.put("password","123456");
        bodyMap.put("name","张三");
        bodyMap.put("age","15");
        HttpEntity<Map> httpEntity = new HttpEntity<Map>(bodyMap, headers);

        ResponseEntity<User> post = restTemplate.exchange(addUrl, HttpMethod.POST, httpEntity, User.class);
        System.out.println("post exchange:"+ post.getBody());
    }
    //提交表单数据
    @RequestMapping("/testPostFormData")
    public void testPostFormData(){
        String addUrl = "http://localhost:8000/user/add2";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //Map bodyMap = new HashMap();
        //bodyMap.put("userName","zhaoliu");
        //bodyMap.put("password","123456");
        //bodyMap.put("name","赵六");
        //bodyMap.put("age","15");
        //HttpEntity<Map> requestEntity = new HttpEntity<Map>(bodyMap, headers);

        //封装参数,不要替换为Map与HashMap,否则参数无法传递
        MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();
        params.add("userName", "zhaoliu");
        params.add("password", "123456");
        params.add("name", "赵六");
        params.add("age", "37");
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(params, headers);

        ResponseEntity<User> post = restTemplate.exchange(addUrl, HttpMethod.POST, requestEntity, User.class);
        System.out.println("post exchange:"+ post.getBody());
    }
}
3. Eureka Server 搭建

搭建eureka-server 服务端

①导入eureka服务端起步依赖

spring-cloud-parent的pom

<!--引入Spring Cloud 依赖-->
    <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>

eureka-server的pom

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

②配置eureka相关配置

server:
  port: 8761
  
eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
    register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要

③引导类加@EnableEurekaServer注解

@SpringBootApplication
// 启用EurekaServer
@EnableEurekaServer
public class EurekaApp {

    public static void main(String[] args) {
        SpringApplication.run(EurekaApp.class,args);
    }
}
4. Eureka控制台

在这里插入图片描述

5. Eureka Client

①导入eureka客户端的起步依赖

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

②配置eureka相关配置

server:
  port: 8001

eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
    fetch-registry: true 
    register-with-eureka: true
spring:
  application:
    name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

③引导类加@EnableEurekaClient注解

package com.ittest.provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient //该注解 在新版本中可以省略
@SpringBootApplication
public class ProviderApp {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}
6. 动态获取路径

①导入起步依赖包

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

②使用DiscoveryClient动态从注册中心获取服务相应实例

package com.ittest.consumer.controller;


import com.ittest.consumer.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * 服务的调用方
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/goods/{id}")
    public Goods findGoodsById(@PathVariable("id") int id){
        System.out.println("findGoodsById..."+id);


        /*
            //远程调用Goods服务中的findOne接口
            使用RestTemplate
            1. 定义Bean  restTemplate
            2. 注入Bean
            3. 调用方法
         */
        /*
            动态从Eureka Server 中获取 provider 的 ip 和端口
             1. 注入 DiscoveryClient 对象.激活
             2. 调用方法
         */

        //演示discoveryClient 使用
        List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");

        //判断集合是否有数据
        if(instances == null || instances.size() == 0){
            //集合没有数据
            return null;
        }

        ServiceInstance instance = instances.get(0);
        String host = instance.getHost();//获取ip
        int port = instance.getPort();//获取端口
        System.out.println(host);
        System.out.println(port);

        String url = "http://"+host+":"+port+"/goods/findOne/"+id;
        // 3. 调用方法
        Goods goods = restTemplate.getForObject(url, Goods.class);

        return goods;
    }
}

③引导类加@EnableDiscoveryClient注解

package com.ittest.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}
7. Eureka属性-instance相关属性
eureka:
  instance:
    hostname: localhost # 主机名
    prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
    ip-address: 127.0.0.1 # 设置当前实例的ip
    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
    lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
    lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信

回环ip 和 私有ip

私有IP地址:
	不需要向有关IP管理机构申请,但只能供内网使用,而且同一内网中不能将同一IP分配给不同的主机。不能	用在互联网上的路由。
	
回环ip:
	127.0.0.1 ---> 127.255.255.254
	网络号全为0表示:该IP是一个保留IP,本网络保留作为本地软件环回测试(loopback test)本主机的进程间的通信之用。若主机发送一个目的地址为环回地址的IP数据报,则本主机中的协议软件就处理该数据报中数据,而不会将数据报发送到任何网络。目的地址为环回地址的IP数据报永远不会出现在任何网络上,因为网络号为127的地址根本不是网络地址。
8. Eureka属性-server相关属性

eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
    register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
  server:
    enable-self-preservation: true # 关闭自我保护机制 true是开启(默认,线上环境) false是关闭(开发环境)
    eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔

在这里插入图片描述
在这里插入图片描述

8.Eureka高可用

搭建 eureka-server-1 和 eureka-server-2

相互注册

eureka-server-1 application.yml配置文件

server:
  port: 8761

eureka:
  instance:
    hostname: eureka-server1 # 主机名
  client:
    service-url:
      defaultZone: http://eureka-server2:8762/eureka
    register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要

spring:
  application:
    name: eureka-server-ha

eureka-server-2 application.yml配置文件

server:
  port: 8762

eureka:
  instance:
    hostname: eureka-server2 # 主机名
  client:
    service-url:
      defaultZone: http://eureka-server1:8761/eureka

    register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
spring:
  application:
    name: eureka-server-ha

配置hosts文件

在这里插入图片描述

9. Eureka高可用-客户端测试
server:
  port: 8001

eureka:
  instance:
    hostname: localhost # 主机名
    prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
    ip-address: 127.0.0.1 # 设置当前实例的ip
    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
    lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
    lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~
  client:
    service-url:
      defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值