【Pigeon源码阅读】服务发现与调用初始化流程解析(五)

测试代码

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

public static void main(String[] args) throws Exception {
   
    InvokerConfig<EchoService> invokerConfig = new InvokerConfig<>(EchoService.class);
    EchoService echoService = ServiceFactory.getService( invokerConfig);
    System.out.println("echoService result:" + echoService.echo("echoService_input"));
}

调用ServiceFactory.getService创建流程:

  1. 创建一个InvokerConfig,至少传入一个接口类全限定名
  2. 调用ServiceFactory.getService(invokerConfig)获取具体的代理对象
  3. 以接口引用,直接通过代理对象调用远程方法

InvokerConfig定义

每个InvokerConfig对应一个调用服务,内部属性定义如下:

public class InvokerConfig<T> {
   
    private static final Logger logger = LoggerLoader.getLogger(InvokerConfig.class);

    /* 调用方式 */
    // 同步调用,客户端线程会阻塞等待返回结果,默认设置是sync模式。
    public static final String CALL_SYNC = CallMethod.SYNC.getName();
    // 回调方式,客户端将请求提交给pigeon后立即返回,也不等待返回结果,它与future方式的区别是
    // callback必须提供一个实现了pigeon提供的InvocationCallback接口的回调对象给pigeon,pigeon负责接收返回结果并传递回给这个回调对象
    public static final String CALL_CALLBACK = CallMethod.CALLBACK.getName();
    // 客户端只是将请求传递给pigeon,pigeon提交给服务端,客户端也不等待立即返回,服务端也不会返回结果给客户端,这种方式一般都是没有返回结果的接口调用。​
    public static final String CALL_ONEWAY = CallMethod.ONEWAY.getName();
    // 客户端将请求提交给pigeon后立即返回,不等待返回结果,由pigeon负责等待返回结果,客户端可以自行决定何时何地来取返回结果
    public static final String CALL_FUTURE = CallMethod.FUTURE.getName();

    /* 服务协议 */
    // 服务器协议,http
    public static final String PROTOCOL_HTTP = Constants.PROTOCOL_HTTP;
    // 服务器协议,tcp
    public static final String PROTOCOL_DEFAULT = Constants.PROTOCOL_DEFAULT;

    /* 序列化方式字段 */
    // hessian序列化方式
    public static final String SERIALIZE_HESSIAN = SerializerType.HESSIAN.getName();
    // java原生序列化方式
    public static final String SERIALIZE_JAVA = SerializerType.JAVA.getName();
    // protostuff序列化方式
    public static final String SERIALIZE_PROTO = SerializerType.PROTO.getName();
    // json序列化方式
    public static final String SERIALIZE_JSON = SerializerType.JSON.getName();
    // FST序列化方式
    public static final String SERIALIZE_FST = SerializerType.FST.getName();

    // 配置中心
    private ConfigManager configManager = ConfigManagerLoader.getConfigManager();

    // 服务接口
    private Class<T> serviceInterface;

    // 服务访问url
    private String url;

    // 服务访问版本
    private String version;

    // 方法调用方式字节
    private byte callMethod = CallMethod.SYNC.getCode();

    // 方法调用方式字符串
    private String callType = CallMethod.SYNC.getName();

    // HESSIAN序列化方式眦裂
    private byte serialize = SerializerType.HESSIAN.getCode();

    // 调用超时时间
    private int timeout = configManager.getIntValue(Constants.KEY_INVOKER_TIMEOUT, Constants.DEFAULT_INVOKER_TIMEOUT);

    // 调用回调
    private InvocationCallback callback;

    // 泳道
    private String suffix = configManager.getGroup();

    // 负载均衡算法
    private String loadbalance = LoadBalanceManager.DEFAULT_LOADBALANCE;

    // 区域路由策略
    private String regionPolicy = RegionPolicyManager.INSTANCE.DEFAULT_REGIONPOLICY;

    // 是否超时重试
    private boolean timeoutRetry = false;

    // 集群访问策略
    private String cluster = Constants.CLUSTER_FAILFAST;

    // 重试次数
    private int retries = 1;

    // 虚拟ip
    private String vip;

    // 最大请求数限制
    private int maxRequests = configManager.getIntValue(Constants.KEY_INVOKER_MAXREQUESTS, 0);

    // 服务协议
    private String protocol = Constants.PROTOCOL_DEFAULT;

    // 当前服务提供的方法
    private Map<String, InvokerMethodConfig> methods;

    private ClassLoader classLoader;

    // 服务访问密钥
    private transient String secret;

    // 远程appkey
    private String remoteAppKey;

    private Object mock;
}

服务调用方静态初始化流程

ServiceFactory静态初始化

ServiceFactory静态初始化流程类似于服务提供方,大致流程如下:

  1. 在首次访问ServiceFactory,会触发ServiceProxy和PublishPolicy的加载
    1. ServiceProxy提供作为调用方的信息注册,和服务代理获取
    2. PublishPolicy针对特定的providerConfig进行服务注册
  2. 随后会调用ProviderBootStrap.init()初始化对外提供服务的基础依赖
    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,初始化注册配置

这里代码和服务提供方的初始化流程大致相同,不再展示,下面主要看服务调用方pigeon初始化流程

ServiceFactory#getService方法实现

在具体调用ServiceFactory.getService时,实际会调用serviceProxy.getProxy(invokerConfig),进一步调用AbstractServiceProxy#getProxy方法,这个方法的实现逻辑大致如下:

  1. 检查interface,url,protocol等参数合法性,如果url没有设置,默认使用接口全限定名,如果protocol不为空,且等于default,则修改成@DEFAULT@,同时更新url加上这个协议前缀
  2. 双重加锁检查invokeConfig对应的服务是否以存在,不存在先尝试启动调用方启动类InvokerBootStrap
  3. 先根据配置的序列方式获取相应的序列化类,再根据invokerConfig创建动态代理:ServiceInvocationProxy
  4. 如果配置中的负载均衡配置存在,注册服务到负载均衡管理器中
  5. 注册区域策略服务
  6. ClientManager.getInstance().registerClients(invokerConfig)注册客户端到注册中心(默认为zk)
  7. 缓存服务
    代码实现逻辑如下:
public <T> T getProxy(InvokerConfig<T> invokerConfig) {
   
    // 参数检查
    if (invokerConfig.getServiceInterface() == null) {
   
        throw new IllegalArgumentException("service interface is required");
    }
    // 如果url没有设置,默认使用接口全限定名
    if (StringUtils.isBlank(invokerConfig.getUrl())) {
   
        invokerConfig.setUrl(ServiceFactory.getServiceUrl(invokerConfig));
    }
    // 如果protocol不为空,且等于default,则修改成@DEFAULT@,同时更新url加上这个协议前缀
    if (!StringUtils.isBlank(invokerConfig.getProtocol())
            && !invokerConfig.getProtocol().equalsIgnoreCase(Constants.PROTOCOL_DEFAULT)) {
   
        String protocolPrefix = "@" + invokerConfig.getProtocol().toUpperCase() + "@";
        if (!invokerConfig.getUrl().startsWith(protocolPrefix)) {
   
            invokerConfig.setUrl(protocolPrefix + invokerConfig.getUrl());
        }
    }
    // 双重检查
    Object service = null;
    service = services.get(invokerConfig);
    if (service == null) {
   
        synchronized (interner.intern(invokerConfig)) {
   
            service = services.get(invokerConfig);
            if (service == null) {
   
                try {
   
                    /
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值