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
<?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>
2, Product entity class goods
@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; }
3, ProductService merchandise Interface
public interface ProductService { // Find all goods List<Product> listProduct(); // Find by product ID Product findById(int id); }
4, ProductServiceImpl commodity implementation class
@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); } }
5、ProductController
@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; } }
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
<?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>
2, ProductOrder goods orders entity
@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; }
3, ProductOrderService Order Interface
/** * Order Business Class */ public interface ProductOrderService { // Under a Single Interface ProductOrder save(int userId, int productId); }
4, ProductOrderServiceImpl order fulfillment class
@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; } }
5、OrderController类
@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); } }
6、SpringBoot启动类
@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(); } }
7、接口测试
多调几次接口,看后台打印
发现订单服务去掉商品服务的时候,不是固定节点,而且集群的每个节点都有可能。所以通过Ribbon实现了负载均衡。
三、Ribbon源码分析
1、@LoadBalanced注解作用
在springcloud中,引入Ribbon来作为客户端时,负载均衡使用的是被@LoadBalanced
修饰的RestTemplate
对象。
RestTemplate 是Spring自己封装的http请求的客户端,也就是说它只能发送一个正常的Http请求,这跟我们要求的负载均衡是有出入的,还有就是这个请求的链接上的域名
是我们微服的一个服务名,而不是一个真正的域名,那它是怎么实现负载均衡功能的呢?
我们来看看RestTemplate的父类InterceptingHttpAccessor。
从源码我们可以知道InterceptingHttpAccessor中有一个拦截器列表List<ClientHttpRequestInterceptor>,如果这个列表为空,则走正常请求流程,如果不为空则走
拦截器,所以只要给RestTemplate添加拦截器,而这个拦截器中的逻辑就是Ribbon的负载均衡的逻辑。通过为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