10分钟零基础带你入门Ribbon小项目-啥?小白都能看懂?


一、前置说明及其框架搭建

1、思路详解

由于设备限制,使用五个端口模拟五个服务(两个注册中心、两个服务提供者、一个服务消费者)其中两个注册中心用来演示Eureka集群的高可用,两个服务提供者用来演示Ribbon的负载均衡,一个服务消费者用来进行远程调用)

#当然官网中是以三个注册中心来演示Eureka集群高可用的,我用两个当然也可以。

如果你了解过zookeeper、consul或者nacos作为注册中心,这个对于你来说就比较简单了。

2、框架搭建

通过聚合工程来创建一个父工程和五个子模块
在这里插入图片描述

二、代码编写

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

在这里插入图片描述

1、编写五个pom文件

1.1、父pom文件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hao</groupId>
    <artifactId>cloud-eureka-demo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>cloud-eureka-server</module>
        <module>cloud-eureka-server02</module>
        <module>service-provider</module>
        <module>service-consumer</module>
        <module>service-provider02</module>
    </modules>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.4.3</version>
    </parent>
    <properties>
        <spring-cloud.version>2020.0.2</spring-cloud.version>
    </properties>

    <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>

</project>

父工程主要就一个cloud依赖和五个子模块以及继承的父依赖。

1.2、子模块pom

1、cloud-eureka-server、cloud-eureka-server02

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-eureka-demo</artifactId>
        <groupId>com.hao</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>
</project>

这两个eureka注册模块pom不被我们熟知的依赖是spring-cloud-starter-netflix-eureka-server,这个依赖继承了eureka相关的所有包(包括Ribbon);导入spring-boot-starter-security的原因是对我们的注册中心客户端需要登录认证

2、service-consumer

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-eureka-demo</artifactId>
        <groupId>com.hao</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-consumer</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

这个spring-cloud-starter-netflix-eureka-client和上面的spring-cloud-starter-netflix-eureka-server是两种服务,从字面意思也应该都明白。

3、service-provider和service-provider02

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-eureka-demo</artifactId>
        <groupId>com.hao</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

2、编写启动类

1、eureka-server子模块的启动类

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

@EnableEurekaServer:该注解是自动识别为注册服务中心

2、eureka-server02子模块的启动类

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

3、service-consumer子模块启动类

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

@EnableEurekaClient注解在最新版已经可以省略

4、service-provider子模块启动类

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

5、service-provider02子模块启动类

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

3、application.yml文件编写

1、eureka-server子模块yml

server:
  port: 8080

spring:
  application:
    name: cloud-eureka-server
  security:
    user:
      name: root
      password: root
eureka:
  instance:
    hostname: eureka01
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    service-url:
      defaultZone: http://root:root@127.0.0.1:${server.port}/eureka/  #注册中心对外暴露的注册地址

2、eureka-server02子模块yml

server:
  port: 8081

spring:
  application:
    name: cloud-eureka-server02
  security:
    user:
      name: root
      password: root
eureka:
  instance:
    hostname: eureka02
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}

  client:
    service-url:
      defaultZone: http://root:root@127.0.0.1:8080/eureka/

3、eureka-consumer子模块yml

server:
  port: 9090
spring:
  application:
    name: service-consumer

eureka:
  instance:
    hostname: consumer
    prefer-ip-address: true
    instance-id: http://${spring.cloud.client.ip-address}:${server.port}

  client:
#    fetch-registry: false
#    register-with-eureka: false
    service-url:
      defaultZone: http://root:root@127.0.0.1:8080/eureka/,http://root:root@127.0.0.1:8081/eureka/

4、service-provider子模块yml

server:
  port: 7070
spring:
  application:
    name: service-provider

eureka:
  instance:
    hostname: provider
    prefer-ip-address: true
    instance-id: http://${spring.cloud.client.ip-address}:${server.port}

  client:
    service-url:
      defaultZone: http://root:root@127.0.0.1:8080/eureka/,http://root:root@127.0.0.1:8081/eureka/

5、service-provider02子模块pom

server:
  port: 7071
spring:
  application:
    name: service-provider    #集群下的名字是相同的

eureka:
  instance:
    hostname: provider02
    prefer-ip-address: true		#是否使用ip形式显示
    instance-id: http://${spring.cloud.client.ip-address}:${server.port}

  client:
    service-url:
      defaultZone: http://root:root@127.0.0.1:8080/eureka/,http://root:root@127.0.0.1:8081/eureka/

4、config文件配置

cloud-eureka-server 、cloud-eureka-server02

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    //关闭某个path下的csrf,否者provider无法注册进去
        super.configure(http);
        http.csrf().ignoringAntMatchers("/eureka/**");
    }
}

service-consumer

@Configuration
public class ConsumerConfig {

    @Bean
//    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

5、编写controller层

service-consumer

@RestController
public class OrderController {

    @Resource
    private OrderService orderService;

    @GetMapping(value ="/order/{id}")
    public Order getOrderById(@PathVariable("id") Integer id) {
        return orderService.selectOrderById(id);
    }
}

service-provider 、service-provider02

@RestController
@RequestMapping(value = "/product")
public class ProductController {

    @Resource
    private ProductService productService;

    @GetMapping(value = "/list")
    public List<Product> getProductList() {
        return productService.selectProductList();
    }
}

6、entity层

service-consumer

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    private Integer id;
    private String orderNo;
    private String orderAddress;
    private Double totalPrice;
    private List<Product> productList;

}

service-provider 、service-provider02

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;
}

7、service层

service-consumer

public interface OrderService {
    Order selectOrderById(Integer id);
}
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Override
    public Order selectOrderById(Integer id) {
        return new Order(id, "order-1", "china", 1024D ,getProductListByLoadBalancerClient());
    }

    public List<Product> getProductListByDiscoveryClient() {
        StringBuffer sb = null;
        List<String> services = discoveryClient.getServices();
        if (CollectionUtils.isEmpty(services)) {
            return null;
        }
        //获取name为service-provider的服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances("service-provider");
        if (CollectionUtils.isEmpty(instances)) {
            return null;
        }
        ServiceInstance serviceInstance = instances.get(0);
        sb = new StringBuffer();
		//拼接地址
        sb.append("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/list");
        ResponseEntity<List<Product>> exchange = restTemplate.exchange(sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {
        });
        return exchange.getBody();
    }

    public List<Product> getProductListByLoadBalancerClient() {
        StringBuffer sb = null;
        ServiceInstance instance = loadBalancerClient.choose("service-provider");
        if (instance == null) {
            return null;
        }
        sb = new StringBuffer();
        sb.append("http://"+instance.getHost()+":"+instance.getPort()+"/product/list");
        System.out.println(instance.getHost()+":"+instance.getPort());
        ResponseEntity<List<Product>> exchange = restTemplate.exchange(sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {
        });
        return exchange.getBody();
    }
    public List<Product> getProductListByAnnotation() {
        ResponseEntity<List<Product>> exchange = restTemplate.exchange("http://service-provider/product/list", HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {
        });
        System.out.println(exchange);
        return exchange.getBody();
    }
}

这是演示的三种方式实现

service-provider 、service-provider02

public interface ProductService {

    List<Product> selectProductList();
}
@Service
public class ProductServiceImpl implements ProductService {
    @Override
    public List<Product> selectProductList() {
        return Arrays.asList(
                new Product(1, "HuaWei nova3", 100, 2999.0),
                new Product(2, "xiaomi", 99, 1999.0),
                new Product(3, "vivo", 102, 2999.0)
        );
    }
}

#使用Arrays.asList模拟返回数据

三、测试

在这里插入图片描述
访问http://localhost:8080/(账号和密码是在配置文件中配置的)
在这里插入图片描述
在这里插入图片描述
Eureka的高可用集群也搭建成功了

访问http://localhost:9090/order/1
在这里插入图片描述
服务间调用也成功!

下面多次刷新该页面,查看控制台打印结果
在这里插入图片描述
负载均衡!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thecoastlines

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值