手写一套简单的dubbo(含注册中心)之核心代码

专栏目录:*
Dubbo基础: https://blog.csdn.net/qq_38310244/article/details/125891802
Dubbo实战: https://blog.csdn.net/qq_38310244/article/details/125892120
手写一套简单的dubbo(含注册中心)之编程思想: https://blog.csdn.net/qq_38310244/article/details/125892641
手写一套简单的dubbo(含注册中心)之核心代码: https://blog.csdn.net/qq_38310244/article/details/125892849

上一篇:手写一套简单的dubbo(含注册中心)之编程思想

代码实现(基于Springboot注解开发)

既然有思路,疑问点都没问题了,就可以开始打码了

代码已上传到GitHub:https://github.com/simple-mine/rpc

创建一个干净的Maven项目,方便依赖的管理

声明注解

首先,我们需要标记出哪些类需要进行代理,还需要声明项目是否使用我们开发的rpc框架。

EnableRPC

定义一个注解类EnableRPC,标识服务消费者是否启用RPC,并在注解类中定义referencePackage属性,标识哪些类需要生成代理,定义clientRegisterIp声明注册中心的地址

package com.simple.rpc.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author: huangjun
 * @Date: 2022/7/13 11:27
 * @Version 1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EnableRPC {
   

    //消费者需要注入远程接口的包名
    String referencePackage() default "";

    //注册中心ip
    String clientRegisterIp() default "";
}

StratRPC

定义注解类StratRPC,标识服务提供者是否启用RPC,并在注解类中定义registerPackage属性,标识哪些类是接口的实现类(需要生成代理的类),serverPort属性标识服务监听的端口(服务启动后,需要一个端口监听来自服务消费者的请求),serverRegisterIp声明注册中心地址

package com.simple.rpc.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author: huangjun
 * @Date: 2022/7/12 10:01
 * @Version 1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface StratRPC {
   

    //需要注册的服务所在的包
    String registerPackage() default "";

    //服务监听的端口
    int serverPort() default 0;

    //注册中心ip
    String serverRegisterIp() default "";


}

RegisterService

定义RegisterService注解类,用于标识服务提供者哪些类是真真切切需要生成代理对象的,虽然前面已经需要生成代理类的包,但是不一定该包路径下的类都需要生成代理对象,这是对需要生成代理对象的类更加细化

package com.simple.rpc.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author: huangjun
 * @Date: 2022/7/8 10:12
 * @Version 1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RegisterService {
   

    String name() default "";
}

Reference

定义注解类Reference,用于标识服务消费者哪些类里需要引用到远程服务提供者提供的服务,在Springboot启动时,为这些成员变量注入代理对象

package com.simple.rpc.annotations;

import java.lang.annotation.*;

/**
 * @Author: huangjun
 * @Date: 2022/7/8 10:09
 * @Version 1.0
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Reference {
   
    String name() default "";
}

代理工厂

AbstractInterfaceFactory

创建服务消费者创建代理对象工厂抽象类AbstractInterfaceFactory,该类用于创建服务消费者需要生成代理对象的成员变量。该类定义了一个调用远程服务的抽象方法,并定义内部类默认实现该抽象方法的具体实现方式。

package com.simple.rpc.factory;

/**
 * @Author: huangjun
 * @Date: 2022/7/11 12:00
 * @Version 1.0
 */

import com.simple.rpc.socket.SocketRequest;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Logger;

/**
 * 代理工厂
 */
public abstract class AbstractInterfaceFactory {
   
    protected static final Logger logger = Logger.getLogger(AbstractInterfaceFactory.class.getName());

    public static AbstractInterfaceFactory getInstance() {
   
        return new DefaultInterfaceFactory();
    }

    protected AbstractInterfaceFactory(){
   }

    public <T> T getWebService(Class<T> oldInterface) {
   
        InterfaceHandler intr = new InterfaceHandler(this);
        return  (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{
   oldInterface}, new InterfaceHandler(this));
    }

    /**
     * 子类实现
     */
    protected abstract Object remoteCall(Method methodName, Object[] args);

    /**
     * 代理类
     */
    private static final class InterfaceHandler implements InvocationHandler {
   
        private AbstractInterfaceFactory factory;

        public InterfaceHandler(AbstractInterfaceFactory factory) {
   
            this.factory = factory;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
   
            String remoteMethodName = method.getName();
            logger.info("开始调用接口:" + remoteMethodName);
            Object rst = factory.remoteCall(method, args);
            logger.info("完成调用");
            return rst;
        }
    }

    /**
     * 静态工厂的默认实现
     */
    private static final class DefaultInterfaceFactory extends AbstractInterfaceFactory {
   
        @Override
        protected Object remoteCall(Method method, Object[] args) {
   
            logger.info("远程方法调用中.....");
            return SocketRequest.sendRequest(method,args);
        }
    }
}

ProxyConfig

创建ProxyConfig类,用于扫描服务消费者哪些类需要注入或实例化代理对象

package com.simple.rpc.config;

import com.simple.rpc.annotations.Reference;
import com.simple.rpc.factory.AbstractInterfaceFactory;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Set;

/**
 * @Author: huangjun
 * @Date: 2022/7/11 18:41
 * @Version 1.0
 */
@Component
public class ProxyConfig{
   

    public static void initReference(ApplicationContext applicationContext,String referencePackage){
   
        //反射工具包,指明扫描路径
        Reflections reflections = new Reflections(new ConfigurationBuilder()
                .setUrls(ClasspathHelper.forPackage(referencePackage))
                .setScanners(new FieldAnnotationsScanner()));

        Set<Field> fields = reflections.getFieldsAnnotatedWith(Reference.class);
        for (Field field : fields) {
   
            //获取需要远程调用的属性字段
            Reference reference = field.getAnnotation(Reference.class);
            if (reference != null) {
   
                try {
   
                    //获取代理对象
                    Object webService = AbstractInterfaceFactory.getInstance().getWebService(field.getType());
                    //允许字段赋值
                    field.setAccessible(true);
                    Object bean;
                    if (applicationContext == null){
   
                        //非容器化启动时
                        bean = field.getDeclaringClass().newInstance();
                    }else {
   
                        //获取容器里该字段的类
                        bean = applicationContext.getBean(field.getDeclaringClass());
                    }
                    //对字段进行赋值
                    field.set(bean, webService);
                } catch (Exception e) {
   
                    e.printStackTrace();
                }
            }
        }
    }
}

ServerInterfaceFactory

创建ServerInterfaceFactory类,用于为服务提供者创建代理对象

package com.simple.rpc.factory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author: huangjun
 * @Date: 2022/7/8 16:53
 * @Version 1.0
 */
public class ServerInterfaceFactory implements InvocationHandler {
   
    /**
     * 1. 目标类
     */
    private final Object target;

    public ServerInterfaceFactory(Object target) {
   
        this.target = target;
    }

    /**
     * 2. 代理逻辑
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
        //调用目标方法
        Object result = null;
        try {
   
            //前置通知
            result = method.invoke(target, args);
        } catch (Exception e) {
   
            e.printStackTrace();
            //异常通知, 可以访问到方法出现的异常
            System.out.println( "方法调用出现了异常");
        }
        //后置通知.
        System.out.println( "方法调用完成!");
        return result;
    }

    /**
     * 3. 获取目标类代理
     */
    public Object getProxy() {
   
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
    }
}

远程调用服务提供者

SocketRequest

创建SocketRequest类,用于实现服务消费者调用远程服务提供者的具体实现(通过Socket方式进行调用)

package com.simple.rpc.socket;

import com.simple.rpc.main.RPCMain;
import com.simple.util.entiy.TCPConfig;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;

/**
 * @Author: huangjun
 * @Date: 2022/7/12 18:01
 * @Version 1.0
 */
public class SocketRequest {
   

    public static Object sendRequest(Method method, Object[] args){
   
        // 获取到远程类
        String methodName = method.getName();
        String serverName = method.getDeclaringClass().getTypeName() + "."+methodName;
        TCPConfig tcpConfig = RPCMain.getTcpMap().get(serverName);
        if (tcpConfig == null){
   
            throw new RuntimeException("can not find provider");
        }
        return sendAndReceive(tcpConfig.getIp(),tcpConfig.getPort(),serverName,methodName,args);
    }

    private static Object sendAndReceive<
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值