【Pigeon源码阅读】服务注册发布流程(四)

测试代码

以下面最小化代码初始pigeon服务提供者为例,分析pigeon完成服务注册的流程:

public static void main(String[] args) throws Exception {
   
    // 初始化ProviderConfig,服务接口是EchoService,具体服务提供者是EchoServiceDefaultImpl
    ProviderConfig<EchoService> providerConfig = new ProviderConfig<>(EchoService.class,
            new EchoServiceDefaultImpl());
    // 注册服务
    ServiceFactory.addService(providerConfig);

    System.in.read();
}

ProviderConfig定义

每个接口服务都以一个ProviderConfig类作为元数据,里面定义的相关属性如下:

// T为提供服务的抽象接口类型
public class ProviderConfig<T> {
   

    // 提供服务的抽象接口类型
    private Class<?> serviceInterface;
    // 访问服务的url
    private String url;
    // 服务版本,调用时会附到url上区分不同版本调用
    private String version;
    // 具体服务示例类
    private T service;
    // 服务器配置
    private ServerConfig serverConfig = new ServerConfig();
    // 是否已发布
    private boolean published = false;
    // 调用超时
    private boolean cancelTimeout = Constants.DEFAULT_TIMEOUT_CANCEL;
    // 配置中心
    private ConfigManager configManager = ConfigManagerLoader.getConfigManager();
    // 如果useSharedPool为false,pigeon就会为每个方法设置独立的线程池执行请求。
    private boolean useSharedPool = configManager.getBooleanValue(Constants.KEY_SERVICE_SHARED,
            Constants.DEFAULT_SERVICE_SHARED);
    // 保存当前服务接口的相关调用方法
    private Map<String, ProviderMethodConfig> methods;
    // 单独设置某个方法的最大并发数,如果并发超过设置的最大并发数,服务端会抛出com.dianping.pigeon.remoting.common.exception.RejectedException异常,客户端也会收到这个异常。
    private int actives = 0;

    // 是否支持新协议,如thrift
    private boolean supported;
    // 独立线程池配置,通过poolConfig --> threadPool找到对应的线程池实例
    private PoolConfig poolConfig;
}

ServerConfig配置

如果说一个ProviderConfig映射一个服务调用接口,一个ServerConfig则对应一个服务器进程,具体服务器可能为基于netty的RPC服务器或jetty的http服务器。
ServerConfig相关配置如下:

public class ServerConfig {
   

    // 配置中心,默认为本地文件,可以拓展为zk,mysql或其他的存储中心
    private static ConfigManager configManager = ConfigManagerLoader.getConfigManager();
    // 默认非http服务器的监听端口
    public static final int DEFAULT_PORT = getDefaultPort();
    // 默认http服务器的监听端口
    public static final int DEFAULT_HTTP_PORT = 4080;
    // 实际非http服务器的监听端口
    private int port = configManager.getIntValue("pigeon.server.defaultport", DEFAULT_PORT);
    // 实际http服务器的监听端口
    private int httpPort = configManager.getIntValue("pigeon.httpserver.defaultport", DEFAULT_HTTP_PORT);
    // 是否允许在端口冲突时,自动选择新端口
    private boolean autoSelectPort = true;
    private boolean enableTest = configManager
            .getBooleanValue(Constants.KEY_TEST_ENABLE, Constants.DEFAULT_TEST_ENABLE);
    // 处理服务请求的线程池核心数
    private int corePoolSize = Constants.PROVIDER_POOL_CORE_SIZE;
    // 处理服务请求的线程池最大数
    private int maxPoolSize = Constants.PROVIDER_POOL_MAX_SIZE;
    // 处理服务请求的线程池最大队列容量
    private int workQueueSize = Constants.PROVIDER_POOL_QUEUE_SIZE;
    // 
    private String suffix = configManager.getGroup();
    // 服务器访问协议,default=tcp或http
    private String protocol = Constants.PROTOCOL_DEFAULT;
    // 当前环境,区分不同环境调用,如dev,prod等。
    private String env;
    // 当前服务ip
    private String ip;
    // 最终监听端口,在port的基础上,可能因为实际监听冲突改变
    private int actualPort = port;
}

服务提供方静态初始化流程

ServiceFactory静态初始化

在示例中,通过一行代码:ServiceFactory.addService(providerConfig)来完成服务注册,在具体调用方法前,会触发ServiceFactory的静态初始化,具体初始化工作包括三部分:

  1. 初始化serviceProxy,提供作为调用方的信息注册,和服务代理获取
  2. 初始化publishPolicy,针对特定的providerConfig进行服务注册
  3. 调用ProviderBootStrap.init()初始化调用ProviderBootStrap

ProviderBootStrap初始化流程

ProviderBootStrap是服务提供者的核心启动类,内部包括以下初始化流程:

  1. ProviderProcessHandlerFactory.init()初始化所有相关拦截器
  2. SerializerFactory.init()初始化所有序列化方式
  3. ClassUtils.loadClasses(“com.dianping.pigeon”)预加载所有pigeon相关类
  4. 注册关闭钩子ShutdownHookListener,内部调用ServiceFactory.unpublishAllServices()进程完成相关清理工作
  5. RegistryManager.getInstance() 初始化注册管理器
  6. 加载服务器,默认包括NettyServer和JettyHttpServer,当前会注册HTTP服务器
    1. 启动http服务器,默认注册到4080
    2. 设置consoleServer,初始化注册配置

在初始化前,通过双重检查判断是否已经初始化,具体实现源码如下所示:

public static void init() {
   
    if (!isInitialized) {
   
        synchronized (ProviderBootStrap.class) {
   
            if (!isInitialized) {
   
                // 初始化所有相关拦截器
                ProviderProcessHandlerFactory.init();
                // 初始化所有序列化方式
                SerializerFactory.init();
                // 加载所有pigeon相关类
                ClassUtils.loadClasses("com.dianping.pigeon");
                // 注册关闭钩子,进程清理工作
                Thread shutdownHook = new Thread(new ShutdownHookListener());
                shutdownHook.setDaemon(true);
                shutdownHook.setPriority(Thread.MAX_PRIORITY);
                Runtime.getRuntime().addShutdownHook(shutdownHook);
                ServerConfig config = new ServerConfig();
                // 设置配置协议为http
                config.setProtocol(Constants.PROTOCOL_HTTP);
                //确保注册管理器已被初始化
                RegistryManager.getInstance();
                // 加载服务器,包括NettyServer和JettyHttpServer
                List<Server> servers = ExtensionLoader.getExtensionList(Server.class);
                for (Server server : servers) {
   
                    if (!server.isStarted()) {
   
                        // config的协议类型是http,因而只初始化HttpServer
                        if (server.support(config)) {
   
                            server.start(config);
                            registerConsoleServer(config);
                            initRegistryConfig(config);

                            httpServer = server;
                            serversMap.put(server.getProtocol() + server.getPort(), server);
                            logger.warn("pigeon " + server + "[version:" + VersionUtils.VERSION + "] has been started");
                        }
                    }
                }
                isInitialized = true;
            }
        }
    }
}

注册服务调用请求的处理拦截器

在pigeon中,发送和接受处理请求实际上都通过一系列的拦截器链实现,结合拦截器链,我们可以很方便地通过定义一个拦截器,添加到拦截器链中来拓展我们自己的逻辑,具体注册的拦截器如下所示,具体每个拦截器的实现原理在服务被调用部分文档解析:

public static void init() {
   
    /*
    业务逻辑拦截器开始
     */
    // 调用链追踪拦截器,记录分布式链路追踪上下文
    registerBizProcessFilter(new TraceFilter());
    if (Constants.MONITOR_ENABLE) {
   
        // 调用监控拦截器,添加调用上下文信息打点
        registerBizProcessFilter(new MonitorProcessFilter());
    }
    // 记录当前处理流程,处理自定义拦截器逻辑,在拦截器回调时调用ProviderProcessInt
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值