SpringCloud (4) ---- Ribbon service calls, source code analysis SpringCloud (3) --- Eureka service registration and discovery

Benpian analog service call orders goods and services, while goods and services using cluster deployment.

Registry service port number 7001, order service port number 9001, commodity cluster port number: 8001,8002,8003.

Each service profile does not show up here on my side, and on the blog post the same configuration. Blog address: SpringCloud (3) --- Eureka service registration and discovery

 

First, Commodities Center server

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

<groupId>com.jincou</groupId>
<artifactId>product</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>product</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--定义当前springcloud版本-->
<spring-cloud.version>Finchley.RELEASE</spring-cloud.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 Client客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

pom.xml

Copy the code
<?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.jincou</groupId>
    <artifactId>product</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>product</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <! - Defines the current version springcloud ->
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.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>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </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>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
Copy the code

  2, Product entity class goods

Copy the code
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {

    private int id;
    //product name
    private String name;
    // price, is divided into units
    private int price;
    //in stock
    private int store;
}
Copy the code

   3, ProductService merchandise Interface

Copy the code
public interface ProductService {

    // Find all goods
    List<Product> listProduct();

    // Find by product ID
    Product findById(int id);
}
Copy the code

   4, ProductServiceImpl commodity implementation class

Copy the code
@Service
public class ProductServiceImpl implements ProductService {

    private static final Map<Integer, Product> daoMap = new HashMap<>();

    // simulation database product data
    static {
        Product p1 = new Product (1, "Apple X", 9999, 10);
        Product p2 = new Product(2, "冰箱", 5342, 19);
        Product p3 = new Product (3, "washing machine", 523, 90);
        Product p4 = new Product (4, "telephone", 64 345, 150);

        daoMap.put(p1.getId(), p1);
        daoMap.put(p2.getId(), p2);
        daoMap.put(p3.getId(), p3);
        daoMap.put(p4.getId(), p4);
    }

    @Override
    public List<Product> listProduct() {
        Collection<Product> collection = daoMap.values();
        List<Product> list = new ArrayList<>(collection);
        return list;
    }
    @Override
    public Product findById(int id) {
        return daoMap.get(id);
    }
}
Copy the code

     5、ProductController

Copy the code
@RestController
@RequestMapping("/api/v1/product")
public class ProductController {

    // cluster under circumstances, order service for viewing in the end product which is called micro-serving node
    @Value("${server.port}")
    private String port;

    @Autowired
    private ProductService productService;

     // Get a list of all the goods
    @RequestMapping("list")
    public Object list(){
        return productService.listProduct();
    }

    // Find Product Details according to id
    @RequestMapping("find")
    public Object findById(int id){
        Product product = productService.findById(id);
        Product result = new Product();
        BeanUtils.copyProperties (product, result);
        result.setName( result.getName() + " data from port="+port );
        return result;
    }
}
Copy the code

      6, measured at the service interface is successful

 

Second, the center server orders

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

<groupId>com.jincou</groupId>
<artifactId>order</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>order</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.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.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

pom.xml

Copy the code
<?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.jincou</groupId>
    <artifactId>order</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>order</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.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.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </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>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
Copy the code

   2, ProductOrder goods orders entity

Copy the code
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductOrder implements Serializable {  
    // order ID
    private int id;
    // product name
    private String productName;
    //order number
    private String tradeNo;
    // price points
    private int price;
    // order creation time
    private Date createTime;
    // user id
    private int userId;
    //username
    private String userName;
}
Copy the code

     3, ProductOrderService Order Interface

Copy the code
/**
 * Order Business Class
 */
public interface ProductOrderService {
     // Under a Single Interface
     ProductOrder save(int userId, int productId);
}
Copy the code

     4, ProductOrderServiceImpl order fulfillment class

Copy the code
@Service
public class ProductOrderServiceImpl implements ProductOrderService {

    @Autowired
    private rest Rest Template template;

    @Override
    public ProductOrder save(int userId, int productId) {
        // product-service micro service name (here point to trade micro service name), api / v1 / product / find? Id =? Is the external interface of goods micro-services
        Map<String, Object> productMap = restTemplate.getForObject("http://product-service/api/v1/product/find?id=" + productId, Map.class);

        ProductOrder productOrder = new ProductOrder();
        productOrder.setCreateTime(new Date());
        productOrder.setUserId(userId);
        productOrder.setTradeNo(UUID.randomUUID().toString());
        // Get trade names and commodity prices
        productOrder.setProductName(productMap.get("name").toString());
        productOrder.setPrice(Integer.parseInt(productMap.get("price").toString()));
        
        // because the goods micro-cluster service configuration, so the print is called here look which cluster node, the output port number.
        System.out.println(productMap.get("name").toString());
        return productOrder;
    }
}
Copy the code

     5、OrderController类

Copy the code
@RestController
@RequestMapping("api/v1/order")
public class OrderController {
    
    @Autowired
    private ProductOrderService productOrderService;
    
    @RequestMapping("save")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){

    return productOrderService.save(userId, productId);
    }
}
Copy the code

    6、SpringBoot启动类

Copy the code
@SpringBootApplication
public class OrderApplication {

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

    //当添加@LoadBalanced注解,就代表启动Ribbon,进行负载均衡
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
Copy the code

    7、接口测试

多调几次接口,看后台打印

发现订单服务去掉商品服务的时候,不是固定节点,而且集群的每个节点都有可能。所以通过Ribbon实现了负载均衡。

 

三、Ribbon源码分析

    1、@LoadBalanced注解作用

在springcloud中,引入Ribbon来作为客户端时,负载均衡使用的是被@LoadBalanced修饰的RestTemplate对象。

      RestTemplate 是Spring自己封装的http请求的客户端,也就是说它只能发送一个正常的Http请求,这跟我们要求的负载均衡是有出入的,还有就是这个请求的链接上的域名

是我们微服的一个服务名,而不是一个真正的域名,那它是怎么实现负载均衡功能的呢?

我们来看看RestTemplate的父类InterceptingHttpAccessor。

      从源码我们可以知道InterceptingHttpAccessor中有一个拦截器列表List<ClientHttpRequestInterceptor>,如果这个列表为空,则走正常请求流程,如果不为空则走

拦截器,所以只要给RestTemplate添加拦截器,而这个拦截器中的逻辑就是Ribbon的负载均衡的逻辑。通过@LoadBalanced注解为RestTemplate配置添加拦截器。

具体的拦截器的生成在LoadBalancerAutoConfiguration这个配置类中,所有的RestTemplate的请求都会转到Ribbon的负载均衡器上

(当然这个时候如果你用RestTemplate发起一个正常的Http请求时走不通,因为它找不到对应的服务。)这样就实现了Ribbon的请求的触发。

     2.拦截器都做了什么?

上面提到过,发起http后请求后,请求会到达到达拦截器中,在拦截其中实现负载均衡,先看看代码:

      我们可以看到在intercept()方法中实现拦截的具体逻辑,首先会根据传进来的请求链接,获取微服的名字serviceName,然后调用LoadBalancerClient的

execute(String serviceId, LoadBalancerRequest<T> request)方法,这个方法直接返回了请求结果,所以正真的路由逻辑在LoadBalancerClient的实现类中,

而这个实现类就是RibbonLoadBalancerClient,看看execute()的源码:

       首先是获得均衡器ILoadBalancer这个类上面讲到过这是Netflix Ribbon中的均衡器,这是一个抽象类,具体的实现类是ZoneAwareLoadBalancer上面也讲到过,

Each incognito name corresponds to an equalizer, equalizer defenders incognito under the name of all the service list. getLoadBalancer () method to obtain the balancing by serviceId, getServer () method by a corresponding equalizer

Get information needs to be routed to the Server, Server has a specific domain name of the service is calculated in the corresponding routing algorithms. Perform normal Http request obtained after a specific Server, the load balancing logic of the entire request is complete.

In incognito is usually used with Ribbon and Hystrix, in fact, the direct use Ribbon and Hystrix implementation calls between services is not very convenient, usually in the Spring Cloud we use Feign complete the call between services,

The Feign is Ribbon and Hystrix made further facilitate the use of the package, the Ribbon will help you learn to better fulfill Spring Cloud calls between services.

 

 I only occasionally to quiet down, past all the wondering about it. Those who have in the old days there have been naive, even stupid, not worth condemnation. After all, the next day, still very long. Continue to encourage their own,

 At daybreak, but also a new starting point, but also the unknown journey (Col. 6)

 

Reprinted to: https://www.cnblogs.com/qdhxhz/p/9568481.html

 

 

Guess you like

Origin www.cnblogs.com/wllcs/p/12002697.html