feign是一个http请求调用的轻量级框架,可以以java接口注解的方式来调用http请求。springcloud引入feign并集成了ribbon实现客户端负载均衡,作为SpringCloud的RPC框架
封装了Http调用流程,更适合面向接口化的编程思想
1.创建新的maven项目
2.导包
org.springframework.boot
spring-boot-starter-parent
2.2.2.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-openfeign
2.2.2.RELEASE
3.创建启动类
@SpringBootApplication
@EnableFeignClients
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
4.编写FeignService
//value属性在微服务里面是服务名,但是我们当前这不是微服务项目,所以该值无用,但是又必填
@FeignClient(value = "asdf", url = "http://httpbin.org")
public interface FeignService {
@GetMapping("get")
String firstTest();
}
5.编写测试的controller
@RestController
public class TestController {
@Resource
private FeignService feignService;
@GetMapping("test")
public String test(){
return feignService.firstTest();
}
}
1、在浏览器中对feign项目中的接口发起请求,地址:http://127.0.0.1:9090/get。
2、feign项目通过feign框架,对boot项目发起请求,访问对应接口。
3、boot项目收到请求,把数据返回给feign。
4、feign项目吧boot项目返回的数据,传输到浏览器当中。
举例
@FeignClient(value = "panghuhu", url = "http://127.0.0.1:8080")
public interface StudentService {
//这里的GetMapping应和调用接口的注解一致,并且feign能自动反序列化成对应的对象
@GetMapping("selectByNo")
FeignResult<Student> getStudent(
//@RequestParam("nou")用来指示调用接口的参数名
@RequestParam("nou") String no);
}
@RestController
public class TestController {
@Resource
private StudentService studentService;
@Resource
private FeignService feignService;
@GetMapping("get")
public FeignResult<Student> get() {
FeignResult<Student> student = studentService.getStudent("1002");
System.out.println(student);
return student;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pb5ZATAh-1654674573549)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220608084842800.png)]
RPC,远程过程调用,可以像调用本地服务一样调用远端服务
远程过程调用,通常由服务端,客户端,通信网络三部分组成
RPC协议的核心,通信协议,编码协议,序列化格式
服务端模块,用来提供服务
客户端模块,用来调用服务
公共模块,用来给接口提供动态代理类
用来定义client和server之间的交互接口
主要是rpc-client和rpc-server之间的数据交互,client调用bussiness里提供的接口,client和server之间使用socket进行数据传输那么server就需要代理告诉他,client调用的事哪个接口,哪个方法,参数有哪些。
客户端代理类
public class ProxyHandler implements InvocationHandler {
private String ip;
private int port;
public ProxyHandler(String ip, int port) {
this.ip = ip;
this.port = port;
}
@Override
//动态代理方法,主要是给接口生成动态代理类,可以向调用本地方法一样调用远程方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//创建socket对象,连接目标服务器进行数据传输
Socket socket = new Socket(ip, port);
//获取客户端调用的接口
Class<?>[] callInterface = proxy.getClass().getInterfaces();
//获取客户端调用的方法名
String name = method.getName();
//获取客户端该方法的参数类型列表,因为方法可以重载,如果没有类型列表的话,就无法确定到底调用的事哪个方法
Class<?>[] types = method.getParameterTypes();
//向服务端传输数据使用的
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
//输入流是从服务端读取数据使用的
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
out.writeObject(callInterface);
out.writeUTF(name);
out.writeObject(types);
out.writeObject(args);
//主动刷新流数据,把数据推送到服务端
out.flush();
//接受服务端返回的对象
Object object = input.readObject();
if (object instanceof Throwable) {
throw (Throwable) object;
}
socket.shutdownOutput();
return object;
}
}
客户端获取代理类对象
public class RpcClient {
//获取接口代理类对象
public static <T> T getService(Class<T> clazz, String ip, int port) {
ProxyHandler handler = new ProxyHandler(ip, port);
Object o = Proxy.newProxyInstance(RpcClient.class.getClassLoader()
, new Class<?>[]{clazz}, handler);
return (T) o;
}
}
服务端代理类
public class RpcProvider {
private int port = 8080;
public void start() throws Exception {
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务端开启成功");
//死循环,让程序一致运行,持续见天客户端的请求
while (true) {
//accept方法会租了,知道有请求过来为止
Socket socket = serverSocket.accept();
System.out.println("收到客户端的请求");
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
//服务端读取数据的顺序一定要与客户写入的顺序一致
Class<?>[] callInterface = (Class<?>[]) in.readObject();
String name=in.readUTF();
Class<?>[] types= (Class<?>[]) in.readObject();
Object[] args= (Object[]) in.readObject();
out.writeObject("ok");
out.flush();
out.close();
in.close();
socket.close();
}
}
public static void main(String[] args) throws Exception {
RpcProvider provider=new RpcProvider();
provider.start();
}
}