支持同步、异步调用
客户端和服务器之间建立TCP连接,可以一次建立一个,也可以多个调用复用一次链接(建立连接耗时)大公司多用RPC
PRC数据包小
protobuf
thrift
rpc:编解码,序列化,链接,丢包,协议(成本大)
Rest(Http):
http请求,支持多种协议和功能
开发方便成本低
http数据包大
java开发:HttpClient,URLConnection
spring cloud暂时用这种方式
本文主要介绍SpringCloud中三种服务调用方式:
下面上伪代码(服务调用关键代码)
1,@Component
//通过DiscoveryClient从Eureka中获取licensingservice服务的实例数组,并返回第一个实例。
public class ConsumerDiscoveryClient {
@Autowired
private DiscoveryClient discoveryClient;
public ServiceInstance getServiceInstance() {
List
if (serviceInstances.size() == 0) {
return null;
}
return serviceInstances.get(0);
}
public String getUrl(String url) {
ServiceInstance serviceInstance=this.getServiceInstance();
if (serviceInstance==null)
throw new RuntimeException("404 ,NOT FOUND");
String urlR=String.format(url,serviceInstance.getUri().toString());
return urlR;
}
}
测试controller
@RestController
@RequestMapping("test")
public class TestController {
//注意必须new,否则会拦截器拦截,改变URL行为
private RestTemplate restTemplate=new RestTemplate();
@Autowired
private ConsumerDiscoveryClient consumerDiscoveryClient;
@RequestMapping("/getAllEmp")
public List
String url=consumerDiscoveryClient.getUrl("%s/test/getAllEmp");
return restTemplate.getForObject(url,List.class);
}
}
2,
//指明负载均衡算法
@Bean
public IRule iRule() {
return new RoundRobinRule();
}
@Bean
@LoadBalanced //告诉Spring创建一个支持Ribbon负载均衡的RestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
@RestController
@RequestMapping("rest")
public class ConsumerRestController {
@Autowired
private RestTemplate restTemplate;
private final static String SERVICE_URL_PREFIX = "服务名";
@RequestMapping("/getById")
public Emp getById(Long id) {
MultiValueMap
paramMap.add("id", id);
return restTemplate.postForObject(SERVICE_URL_PREFIX + "/test/getById", paramMap, Emp.class);
}
}
3,
@FeignClient(name = "account-service")
public interface AccountFeign {
@PostMapping("/account/insert")
ResultData
@PostMapping("/account/delete")
ResultData
@PostMapping("/account/update")
ResultData
@GetMapping("/account/getByCode/{accountCode}")
ResultData
}
在接口上添加注解@FeignClient(name = "account-service")
,表明这是一个Feign客户端,name属性的配置表示我这个接口最终会转发到accout-service
上。
启动类加@EnableFeignClients
一,新建子工程
pom:
cloud_alibaba_learn
com.liu.learn
1.0-SNAPSHOT
4.0.0
cloud_order
org.springframework.boot
spring-boot-starter-web
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
org.springframework.cloud
spring-cloud-starter-openfeign
配置文件bootstrap.xml
server:
port: 8090
spring:
profiles:
active: dev
application:
main:
allow-bean-definition-overriding: true
name: order-service #服务名
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
控制器类:
package com.liu.controller;
import com.liu.config.ConsumerDiscoveryClient;
import com.liu.entities.CommonResult;
import com.liu.entities.Payment;
import lombok.extern.slf4j.Slf4j;
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.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Slf4j
public class OrderFirstController {
private RestTemplate restTemplate = new RestTemplate();
@Autowired
private ConsumerDiscoveryClient consumerDiscoveryClient;
@GetMapping("/consumer/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id) {
String url = consumerDiscoveryClient.getUrl("%s/payment/get/"+id);
System.out.println("url:"+url);
return restTemplate.getForObject(url,CommonResult.class);
}
}
控制器依赖类
package com.liu.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class ConsumerDiscoveryClient {
@Autowired
private DiscoveryClient discoveryClient;
public ServiceInstance getServiceInstance() {
List serviceInstances = discoveryClient.getInstances("payment-service");
if (serviceInstances.size() == 0) {
return null;
}
for (ServiceInstance serviceInstance : serviceInstances) {
System.out.println("url:"+serviceInstance.getUri());
}
return serviceInstances.get(0);
}
public String getUrl(String url) {
ServiceInstance serviceInstance=this.getServiceInstance();
if (serviceInstance==null)
throw new RuntimeException("404 ,NOT FOUND");
String urlR=String.format(url,serviceInstance.getUri().toString());
return urlR;
}
}
其他
package com.liu.entities;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data //lombok 自动生成getset
@AllArgsConstructor // 有参构造函数
@NoArgsConstructor //无参函数
public class CommonResult {
private Integer code;
private String message;
private T data;
public CommonResult(Integer code,String message){
this(code,message,null);
}
}
package com.liu.entities;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor // 有参构造函数
@NoArgsConstructor //无参函数
public class Payment implements Serializable { //为对象提供标准的序列化与反序列化操作
private Long id;
/**
* 订单号
*/
private String serial;
}
启动类:
package com.liu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class OrderMain {
public static void main(String[] args) {
SpringApplication.run(OrderMain.class, args);
}
}
与第一种方式不同的地方
1,
RestTemplate创建方式
代码只贴出与第一种不同的地方
package com.liu.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
@ComponentScan("org.springframework.boot.actuate.autoconfigure.metrics")
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
package com.liu.controller;
import lombok.extern.slf4j.Slf4j;
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.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Slf4j
public class OrderSecondController {
//实现负载均衡必须为注册中心服务名
//String PAYMENT_URL = "http://localhost:8070/";
String PAYMENT_URL = "http://payment-service/";
@Autowired
private RestTemplate restTemplate ;
@GetMapping("/consumer2/payment/get/{id}")
public com.liu.entities.CommonResult getPaymentById(@PathVariable("id") Long id) {
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id, com.liu.entities.CommonResult.class);
}
}
为了直观展示负载均衡,修改payment-service服务 添加
@Value("${server.port}")
private String serverPort;
package com.liu.controller;
import com.liu.entitis.CommonResult;
import com.liu.entitis.Payment;
import com.liu.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.Resource;
@Slf4j
@RestController
@RequestMapping("/payment")
/**
* 支付controller类
*/
@RefreshScope
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@Resource
private PaymentService paymentService;
@PostMapping(value = "/create")
//添加 前
/**
* 添加 后
*/
public CommonResult create(@RequestBody com.liu.entitis.Payment payment){
boolean result=paymentService.save(payment);
log.info("****插入结果:"+result);
if (result){
return new CommonResult(444,"插入数据库成功",null);
}else {
return new CommonResult(200,"插入数据库失败",result);
}
}
//通过id进行查询
@GetMapping("/get/{id}")
/**
* 通过id进行查询
*/
//通过id查询
public CommonResult getPaymentById(@PathVariable("id") Long id ){
Payment payment = paymentService.getById(id);
log.info("****查询结果:"+payment);
if (payment != null){
return new CommonResult(200,"查询成功"+serverPort,payment);
}else {
return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
}
}
}
导出order-service jar包,以8071端口号运行
package com.liu.controller;
import lombok.extern.slf4j.Slf4j;
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.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Slf4j
public class OrderSecondController {
// String PAYMENT_URL = "http://localhost:8071/";
//服务名
String PAYMENT_URL = "http://payment-service";
@Autowired
private RestTemplate restTemplate ;
@GetMapping("/consumer2/payment/get/{id}")
public com.liu.entities.CommonResult getPaymentById(@PathVariable("id") Long id) {
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id, com.liu.entities.CommonResult.class);
}
}
package com.liu.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
@LoadBalancerClient(name = "payment-service")
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
访问浏览器
两个服务之间进行切换
负载均衡服务切换算法下文讲解
新建feifn调用服务接口
package com.liu.servcie;
import com.liu.entities.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Component
@FeignClient(value = "payment-service")
public interface PaymentFeignService {
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id);
}
新建控制器类
package com.liu.controller;
import com.liu.entities.CommonResult;
import com.liu.servcie.PaymentFeignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderThirdController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping(value = "/consumer3/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
}
修改启动类
package com.liu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderMain {
public static void main(String[] args) {
SpringApplication.run(OrderMain.class, args);
}
}
启动服务进行测试
openfeign已经集成了负载均衡
PaymentFeignService 服务接口类似提供服务类的controller层,不同的是feign客户端为接口类