Feign介绍

1.Feign介绍

feign是一个http请求调用的轻量级框架,可以以java接口注解的方式来调用http请求。springcloud引入feign并集成了ribbon实现客户端负载均衡,作为SpringCloud的RPC框架

Feign解决了什么问题?

封装了Http调用流程,更适合面向接口化的编程思想

2.Feign学习

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();
    }
}

3、测试过程

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;
    }

}

4、原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pb5ZATAh-1654674573549)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220608084842800.png)]

5、RPC(Remote Produce Call Protocal)

RPC,远程过程调用,可以像调用本地服务一样调用远端服务

远程过程调用,通常由服务端,客户端,通信网络三部分组成

RPC协议的核心,通信协议,编码协议,序列化格式

6、手动模拟一个rpc框架

rpc-server

服务端模块,用来提供服务

rpc-client

客户端模块,用来调用服务

rpc-common

公共模块,用来给接口提供动态代理类

rpc-bussiness

用来定义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();
    }
}

你可能感兴趣的:(feign,java,spring,cloud,spring)