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

本文介绍了如何手写一套简单的基于Springboot注解的Dubbo实现,包括声明注解、代理工厂、远程调用、注册中心的接入与实现,以及实际使用案例。详细阐述了各个组件的职责和工作流程,如服务提供者监听端口、服务消费者调用服务、注册中心管理服务列表等。
摘要由CSDN通过智能技术生成

专栏目录:*
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
    评论
Spring Ioc的底层原理是基于反射和依赖注入实现的。在Spring容器启动时,会扫描所有的类,找到其中被注解为@Component、@Service、@Controller、@Repository等的类,并将其实例化为Bean对象,同时将其放入Bean工厂中进行管理。在Bean实例化的过程中,Spring使用反射机制调用构造方法或工厂方法来创建对象,并通过setter或构造方法注入依赖的其他Bean对象。这样,通过Ioc容器的管理,实现了对象之间的解耦和灵活性。 手写一套简单Spring Ioc框架: 1. 定义注解@ComponentScan用于扫描指定包下的所有类,将被注解为@Component、@Service、@Controller、@Repository等的类实例化为Bean对象,并将其放入Bean工厂中进行管理。 ```java @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ComponentScan { String[] basePackages(); } ``` 2. 定义注解@Component用于标注需要实例化为Bean对象的类。 ```java @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Component { String value() default ""; } ``` 3. 定义Bean工厂类,存储所有的Bean对象。 ```java public class BeanFactory { private Map<String, Object> beans = new ConcurrentHashMap<>(); public Object getBean(String name) { return beans.get(name); } public void addBean(String name, Object bean) { beans.put(name, bean); } } ``` 4. 定义Bean扫描器,扫描指定包下的所有类,并将被注解为@Component、@Service、@Controller、@Repository等的类实例化为Bean对象,并将其放入Bean工厂中进行管理。 ```java public class BeanScanner { private BeanFactory beanFactory; public BeanScanner(BeanFactory beanFactory) { this.beanFactory = beanFactory; } public void scan(String... basePackages) { for (String basePackage : basePackages) { String path = basePackage.replaceAll("\\.", "/"); File file = new File(this.getClass().getResource("/" + path).getFile()); if (!file.exists()) { continue; } if (file.isDirectory()) { for (File subFile : file.listFiles()) { scan(basePackage + "." + subFile.getName().replaceAll(".class", "")); } } else { String className = basePackage + "." + file.getName().replaceAll(".class", ""); try { Class<?> clazz = Class.forName(className); if (clazz.isAnnotationPresent(Component.class)) { Object bean = clazz.getDeclaredConstructor().newInstance(); beanFactory.addBean(clazz.getName(), bean); } } catch (Exception e) { e.printStackTrace(); } } } } } ``` 5. 定义注解@Autowired用于依赖注入。 ```java @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { } ``` 6. 定义Bean注入器,通过反射机制注入依赖的Bean对象。 ```java public class BeanInjector { private BeanFactory beanFactory; public BeanInjector(BeanFactory beanFactory) { this.beanFactory = beanFactory; } public void inject() { for (Object bean : beanFactory.beans.values()) { Field[] fields = bean.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Autowired.class)) { try { field.setAccessible(true); Object dependencyBean = beanFactory.getBean(field.getType().getName()); field.set(bean, dependencyBean); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } } ``` 7. 定义Spring Ioc框架的入口类,启动容器,并扫描指定包下的所有类,实例化为Bean对象,并将其放入Bean工厂中进行管理,最后注入依赖的Bean对象。 ```java public class SpringIoc { public static void run(Class<?> clazz, String[] args) { BeanFactory beanFactory = new BeanFactory(); BeanScanner beanScanner = new BeanScanner(beanFactory); ComponentScan componentScan = clazz.getDeclaredAnnotation(ComponentScan.class); beanScanner.scan(componentScan.basePackages()); BeanInjector beanInjector = new BeanInjector(beanFactory); beanInjector.inject(); } } ``` 使用示例: 1. 定义两个类,一个依赖另一个。 ```java @Component public class UserService { public void sayHello() { System.out.println("Hello, World!"); } } @Component public class UserController { @Autowired private UserService userService; public void hello() { userService.sayHello(); } } ``` 2. 定义启动类,指定需要扫描的包,启动Spring Ioc容器。 ```java @ComponentScan(basePackages = "com.example") public class Application { public static void main(String[] args) { SpringIoc.run(Application.class, args); UserController userController = (UserController) BeanFactory.getBean("com.example.UserController"); userController.hello(); } } ``` 输出结果: ``` Hello, World! ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值