nacos服务发现
想要开启服务发现,需要在main函数上添加 @EnableDiscoveryClient 注解
然后我们编写一个controller类来查询nacos中注册的所有微服务以及对应的ip+端口号
@Controller
public class DiscoveryController {
@Autowired
DiscoveryClient discoveryClient;
// 这个方法可以获取nacos中注册的服务信息
@GetMapping("/getServicesInfo")
@ResponseBody
public String getServicesInfo() {
StringBuilder sb = new StringBuilder();
// 查询服务名称和服务的ip+端口号
for (String serviceId : discoveryClient.getServices()) {
sb.append(serviceId + "<br>");
for (ServiceInstance instance : discoveryClient.getInstances(serviceId)) {
sb.append(instance.getHost() + ":" + instance.getPort() + "<br>");
}
}
return sb.toString();
}
}
接着启动微服务,然后在浏览器中调用该接口就可以查到对应的信息
简单下单场景
了解了服务发现的基本内容,我们就可以进行一个简单的下单场景模拟,场景流程如下
首先我们需要给商品服务编写一个根据商品id查询商品的接口
由于我们需要编写bean类,为了方便起见,我们首先给services的配置文件中添加lombok依赖和fastjson依赖
接着我们编写controller类,这个类提供一个查询商品信息的接口
@RestController
public class ProductController {
@Autowired
ProductService productService;
@GetMapping("/getProduct/{id}")
@ResponseBody
public String getProductById(@PathVariable("id") Long productId) {
Product product = productService.getProductById(productId);
return JSON.toJSONString(product);
}
}
接着是商品的bean类
@Data
public class Product {
private Long id;
private BigDecimal price;
private String productName;
private int num;
}
最后是service类
@Service
public class ProductServiceImpl implements ProductService {
@Override
public Product getProductById(Long id) {
Product product = new Product();
product.setId(id);
product.setPrice(new BigDecimal("99"));
product.setProductName("苹果-" + id);
product.setNum(2);
return product;
}
}
在浏览器中调用方法可以获取查询结果
由于微服务之间可能会有相互依赖的模型层,因此需要将共用的模型层的bean类放到一个公共的模块中
需要在model模块中添加lombok依赖
然后在services模块中引入model模块
一下是Order实体类的代码
@Data
public class Order {
private Long id;
private BigDecimal totalAmount;
private Long userId;
private String nickName;
private String address;
private List<Object> productList;
}
接着我们编写order服务的controller
@RestController
public class OrderController {
@Autowired
OrderService orderService;
@GetMapping("/createOrder/{userId}/{productId}")
public String createOrder(@PathVariable Long userId, @PathVariable Long productId) {
Order order = orderService.createOrder(userId, productId);
return JSON.toJSONString(order);
}
}
由于在service中由于需要使用到RestTemplate进行远程调用,因此我们需要编写一个配置类,给容器注入一个RestTemplate实例
@Configuration
public class OrderConfig {
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
最后编写service
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
DiscoveryClient discoveryClient;
@Autowired
RestTemplate restTemplate;
@Override
public Order createOrder(Long userId, Long productId) {
Order order = new Order();
order.setId(2L);
order.setUserId(userId);
Product product = getProductRemote(productId);
BigDecimal totalPrice = product.getPrice().multiply(new BigDecimal(product.getNum()));
order.setTotalAmount(totalPrice);
order.setAddress("福建省");
order.setNickName("小明明");
order.setProductList(Arrays.asList(product));
return order;
}
// 通过远程调用的方式获取商品数据
private Product getProductRemote(Long productId) {
discoveryClient.getInstances("service-product");
List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
String url = "http://" + instances.get(0).getHost() + ":" + instances.get(0).getPort() + "/getProduct/" + productId;
log.info("远程调用:{}", url);
Product product = restTemplate.getForObject(url, Product.class);
return product;
}
}
在浏览器中调用接口就可以获取数据
负载均衡
由于我们的订单服务需要进行负载均衡的调用,因此首先需要添加负载均衡的依赖
接着就是在service中使用 LoadBalancerClient 进行负载均衡的调用
用浏览器进行多次调用得到的测试结果如下
可以发现是交替调用两个商品服务的
除了上述方式外,还可以通过注解的方式进行负载均衡的调用
首先需要在配置类中加上 @LoadBalanced 注解
接着在如下图修改远程调用方法中的url即可