@LoadBalanced:通过注解开启 Ribbon 的负载均衡器
DiscoveryClientSpring Boot 不提供任何自动配置的RestTemplate bean,所以需要在启动类中注入 RestTemplate。
package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; // 开启 @EnableDiscoveryClient 注解,当前版本默认会开启该注解 //@EnableDiscoveryClient @SpringBootApplication public class OrderServiceApplication { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } }OrderServiceImpl.java
package com.example.service.impl; import com.alibaba.fastjson.JSON; import com.example.pojo.Order; import com.example.pojo.Product; import com.example.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; import java.util.List; @Slf4j @Service public class OrderServiceImpl implements OrderService { @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; /** * 根据主键查询订单 * * @param id * @return */ @Override public Order selectOrderById(Integer id) { log.info("订单服务查询订单信息..."); return new Order(id, "order-001", "中国", 22788D, selectProductListByDiscoveryClient()); } private List<Product> selectProductListByDiscoveryClient() { StringBuffer sb = null; // 获取服务列表 List<String> serviceIds = discoveryClient.getServices(); if (CollectionUtils.isEmpty(serviceIds)) return null; // 根据服务名称获取服务 List<ServiceInstance> serviceInstances = discoveryClient.getInstances("product-service"); if (CollectionUtils.isEmpty(serviceInstances)) return null; // 构建远程服务调用地址 ServiceInstance si = serviceInstances.get(0); sb = new StringBuffer(); sb.append("http://" + si.getHost() + ":" + si.getPort() + "/product/list"); log.info("订单服务调用商品服务..."); log.info("从注册中心获取到的商品服务地址为:{}", sb.toString()); // 远程调用服务 // ResponseEntity: 封装了返回数据 ResponseEntity<List<Product>> response = restTemplate.exchange( sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {}); log.info("商品信息查询结果为:{}", JSON.toJSONString(response.getBody())); return response.getBody(); } } LoadBalancerClientOrderServiceImpl.java
package com.example.service.impl; import com.alibaba.fastjson.JSON; import com.example.pojo.Order; import com.example.pojo.Product; import com.example.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.List; @Slf4j @Service public class OrderServiceImpl implements OrderService { @Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; // Ribbon 负载均衡器 /** * 根据主键查询订单 * * @param id * @return */ @Override public Order selectOrderById(Integer id) { log.info("订单服务查询订单信息..."); return new Order(id, "order-001", "中国", 22788D, selectProductListByLoadBalancerClient()); } private List<Product> selectProductListByLoadBalancerClient() { StringBuffer sb = null; // 根据服务名称获取服务 ServiceInstance si = loadBalancerClient.choose("product-service"); if (null == si) return null; sb = new StringBuffer(); sb.append("http://" + si.getHost() + ":" + si.getPort() + "/product/list"); log.info("订单服务调用商品服务..."); log.info("从注册中心获取到的商品服务地址为:{}", sb.toString()); // ResponseEntity: 封装了返回数据 ResponseEntity<List<Product>> response = restTemplate.exchange( sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {}); log.info("商品信息查询结果为:{}", JSON.toJSONString(response.getBody())); return response.getBody(); } } @LoadBalanced启动类注入 RestTemplate 时添加 @LoadBalanced 负载均衡注解,表示这个 RestTemplate 在请求时拥有客户端负载均衡的能力。
package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableDiscoveryClient @SpringBootApplication public class OrderServiceApplication { @Bean @LoadBalanced // 负载均衡注解 public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } }OrderServiceImpl.java
package com.example.service.impl; import com.alibaba.fastjson.JSON; import com.example.pojo.Order; import com.example.pojo.Product; import com.example.service.OrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.List; @Slf4j @Service public class OrderServiceImpl implements OrderService { @Autowired private RestTemplate restTemplate; /** * 根据主键查询订单 * * @param id * @return */ @Override public Order selectOrderById(Integer id) { log.info("订单服务查询订单信息..."); return new Order(id, "order-001", "中国", 22788D, selectProductListByLoadBalancerAnnotation()); } private List<Product> selectProductListByLoadBalancerAnnotation() { String url = "http://product-service/product/list"; log.info("订单服务调用商品服务..."); log.info("从注册中心获取到的商品服务地址为:{}", url); // ResponseEntity: 封装了返回数据 ResponseEntity<List<Product>> response = restTemplate.exchange( url, HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {}); log.info("商品信息查询结果为:{}", JSON.toJSONString(response.getBody())); return response.getBody(); } } 控制层OrderController.java
package com.example.controller; import com.example.pojo.Order; import com.example.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; 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; @RestController @RequestMapping("/order") public class OrderController { @Autowired private OrderService orderService; /** * 根据主键查询订单 * * @param id * @return */ @GetMapping("/{id}") public Order selectOrderById(@PathVariable("id") Integer id) { return orderService.selectOrderById(id); } } 访问刷新 Nacos 服务器,可以看到服务已注册至 Nacos。
访问::9090/order/1 结果如下:
配置 MySQL 数据库Nacos 在 0.7 版本之前,默认使用的是嵌入式数据库 Apache Derby 来存储数据(内嵌的数据库会随着 Nacos 一起启动,无需额外安装);0.7 版本及以后,增加了对 MySQL 数据源的支持。
MySQL数据源环境要求:MySQL 5.6.5+(生产使用建议至少主备模式,或者采用高可用数据库);
初始化 MySQL 数据库创建数据库 nacos_config。
SQL源文件地址:https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql ,或者在 nacos-server 解压目录 conf 下,找到 nacos-mysql.sql 文件,运行该文件,结果如下:
application.properties 配置修改 nacos/conf/application.properties 文件的以下内容。
最终修改结果如下:
#*************** Config Module Related Configurations ***************# ### If user MySQL as datasource: # 指定数据源为 MySQL spring.datasource.platform=mysql Count of DB: 数据库实例数量db.num=1
数据库连接信息,如果是 MySQL 8.0+ 版本需要添加 serverTimezone=Asia/Shanghai Connect URL of DB: