使用Jupiter做rpc框架,实现通过ip+port指定服务处理

最近接到一个需求,需求中需要通过服务的ip+port在注册中心中指定服务来处理请求。
实现方式为:
1、重新实现ProxyFactory类,增加isSpecified属性、unresolvedSocketAddress属性,
增加初始化这两个属性的方法isSpecified,初始化前面两个属性的值;
dispatcher方法增加对isSpecified属性的判断,如果是指定ip的进入新创建的Dispatcher
实现类来处理;
2、新增一个Dispatcher实现类,继承AbstractDispatcher类,将select类里的软负载均衡改为指定。

具体代码如下:

/*
 * Copyright (c) 2015 The Jupiter Project
 *
 * Licensed under the Apache License, version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jupiter.rpc.consumer;

import java.util.Collections;
import java.util.List;

import org.jupiter.common.util.JConstants;
import org.jupiter.common.util.Lists;
import org.jupiter.common.util.Proxies;
import org.jupiter.common.util.Requires;
import org.jupiter.common.util.Strings;
import org.jupiter.rpc.DispatchType;
import org.jupiter.rpc.InvokeType;
import org.jupiter.rpc.JClient;
import org.jupiter.rpc.ServiceProvider;
import org.jupiter.rpc.consumer.cluster.ClusterInvoker;
import org.jupiter.rpc.consumer.dispatcher.CiccOmsDispatcher;
import org.jupiter.rpc.consumer.dispatcher.DefaultBroadcastDispatcher;
import org.jupiter.rpc.consumer.dispatcher.DefaultRoundDispatcher;
import org.jupiter.rpc.consumer.dispatcher.Dispatcher;
import org.jupiter.rpc.consumer.invoker.AsyncInvoker;
import org.jupiter.rpc.consumer.invoker.AutoInvoker;
import org.jupiter.rpc.load.balance.LoadBalancerFactory;
import org.jupiter.rpc.load.balance.LoadBalancerType;
import org.jupiter.rpc.model.metadata.ClusterStrategyConfig;
import org.jupiter.rpc.model.metadata.MethodSpecialConfig;
import org.jupiter.rpc.model.metadata.ServiceMetadata;
import org.jupiter.serialization.SerializerType;
import org.jupiter.transport.*;

/**
 * Proxy factory
 *
 * Consumer对象代理工厂, [group, providerName, version]
 *
 * jupiter
 * org.jupiter.rpc.consumer
 *
 * @author wangjp
 */
public class ProxyFactory {

    // 接口类型
    private final Class interfaceClass;
    // 服务组别
    private String group;
    // 服务名称
    private String providerName;
    // 服务版本号, 通常在接口不兼容时版本号才需要升级
    private String version;

    // jupiter client
    private JClient client;
    // 序列化/反序列化方式
    private SerializerType serializerType = SerializerType.getDefault();
    // 软负载均衡类型
    private LoadBalancerType loadBalancerType = LoadBalancerType.getDefault();
    // 基于ExtSpiLoadBalancerFactory扩展的负载均衡可以选择指定名字, 可以利用名字作为唯一标识扩展多种类型的负载均衡
    private String extLoadBalancerName;
    // provider地址
    private List addresses;
    // 调用方式 [同步, 异步]
    private InvokeType invokeType = InvokeType.getDefault();
    // 派发方式 [单播, 广播]
    private DispatchType dispatchType = DispatchType.getDefault();
    // 是否指定处理节点
    private boolean isSpecified = false;
    // 指定的处理节点地址
    private UnresolvedSocketAddress unresolvedSocketAddress;
    // 调用超时时间设置
    private long timeoutMillis;
    // 指定方法的单独配置, 方法参数类型不做区别对待
    private List methodSpecialConfigs;
    // 消费者端拦截器
    private List interceptors;
    // 集群容错策略
    private ClusterInvoker.Strategy strategy = ClusterInvoker.Strategy.getDefault();
    // failover重试次数
    private int retries = 2;

    public static  ProxyFactory factory(Class interfaceClass) {
        ProxyFactory factory = new ProxyFactory<>(interfaceClass);
        // 初始化数据
        factory.addresses = Lists.newArrayList();
        factory.interceptors = Lists.newArrayList();
        factory.methodSpecialConfigs = Lists.newArrayList();

        return factory;
    }

    private ProxyFactory(Class interfaceClass) {
        this.interfaceClass = interfaceClass;
    }

    public Class getInterfaceClass() {
        return interfaceClass;
    }

    public ProxyFactory group(String group) {
        this.group = group;
        return this;
    }

    public ProxyFactory providerName(String providerName) {
        this.providerName = providerName;
        return this;
    }

    public ProxyFactory version(String version) {
        this.version = version;
        return this;
    }

    public ProxyFactory directory(Directory directory) {
        return group(directory.getGroup())
                .providerName(directory.getServiceProviderName())
                .version(directory.getVersion());
    }

    public ProxyFactory client(JClient client) {
        this.client = client;
        return this;
    }

    public ProxyFactory serializerType(SerializerType serializerType) {
        this.serializerType = serializerType;
        return this;
    }

    public ProxyFactory loadBalancerType(LoadBalancerType loadBalancerType) {
        this.loadBalancerType = loadBalancerType;
        return this;
    }

    public ProxyFactory loadBalancerType(LoadBalancerType loadBalancerType, String extLoadBalancerName) {
        this.loadBalancerType = loadBalancerType;
        this.extLoadBalancerName = extLoadBalancerName;
        return this;
    }

    public ProxyFactory addProviderAddress(UnresolvedAddress... addresses) {
        Collections.addAll(this.addresses, addresses);
        return this;
    }

    public ProxyFactory addProviderAddress(List addresses) {
        this.addresses.addAll(addresses);
        return this;
    }

    public ProxyFactory invokeType(InvokeType invokeType) {
        this.invokeType = Requires.requireNotNull(invokeType);
        return this;
    }

    public ProxyFactory dispatchType(DispatchType dispatchType) {
        this.dispatchType = Requires.requireNotNull(dispatchType);
        return this;
    }

    public ProxyFactory timeoutMillis(long timeoutMillis) {
        this.timeoutMillis = timeoutMillis;
        return this;
    }

    public ProxyFactory addMethodSpecialConfig(MethodSpecialConfig... methodSpecialConfigs) {
        Collections.addAll(this.methodSpecialConfigs, methodSpecialConfigs);
        return this;
    }

    public ProxyFactory addInterceptor(ConsumerInterceptor... interceptors) {
        Collections.addAll(this.interceptors, interceptors);
        return this;
    }

    public ProxyFactory clusterStrategy(ClusterInvoker.Strategy strategy) {
        this.strategy = strategy;
        return this;
    }

    public ProxyFactory failoverRetries(int retries) {
        this.retries = retries;
        return this;
    }

    public ProxyFactory isSpecified(UnresolvedSocketAddress unresolvedSocketAddress){
        this.isSpecified = true;
        this.unresolvedSocketAddress = unresolvedSocketAddress;
        return this;
    }

    public I newProxyInstance() {
        // check arguments
        Requires.requireNotNull(interfaceClass, "interfaceClass");

        ServiceProvider annotation = interfaceClass.getAnnotation(ServiceProvider.class);

        if (annotation != null) {
            Requires.requireTrue(
                    group == null,
                    interfaceClass.getName() + " has a @ServiceProvider annotation, can't set [group] again"
            );
            Requires.requireTrue(
                    providerName == null,
                    interfaceClass.getName() + " has a @ServiceProvider annotation, can't set [providerName] again"
            );

            group = annotation.group();
            String name = annotation.name();
            providerName = Strings.isNotBlank(name) ? name : interfaceClass.getName();
        }

        Requires.requireTrue(Strings.isNotBlank(group), "group");
        Requires.requireTrue(Strings.isNotBlank(providerName), "providerName");
        Requires.requireNotNull(client, "client");
        Requires.requireNotNull(serializerType, "serializerType");

        if (dispatchType == DispatchType.BROADCAST && invokeType == InvokeType.SYNC) {
            throw reject("broadcast & sync unsupported");
        }

        // metadata
        ServiceMetadata metadata = new ServiceMetadata(
                group,
                providerName,
                Strings.isNotBlank(version) ? version : JConstants.DEFAULT_VERSION
        );

        JConnector connector = client.connector();
        for (UnresolvedAddress address : addresses) {
            connector.addChannelGroup(metadata, connector.group(address));
        }

        // dispatcher
        Dispatcher dispatcher = dispatcher()
                .interceptors(interceptors)
                .timeoutMillis(timeoutMillis)
                .methodSpecialConfigs(methodSpecialConfigs);

        ClusterStrategyConfig strategyConfig = ClusterStrategyConfig.of(strategy, retries);
        Object handler;
        switch (invokeType) {
            case SYNC:
            case AUTO:
                handler = new AutoInvoker(client.appName(), metadata, dispatcher, strategyConfig, methodSpecialConfigs);
                break;
            case ASYNC:
                handler = new AsyncInvoker(client.appName(), metadata, dispatcher, strategyConfig, methodSpecialConfigs);
                break;
            default:
                throw reject("invokeType: " + invokeType);
        }

        return Proxies.getDefault().newProxy(interfaceClass, handler);
    }

    protected Dispatcher dispatcher() {
        switch (dispatchType) {
            case ROUND:
                if(isSpecified){
                    return new CiccOmsDispatcher(client,
                            LoadBalancerFactory.getInstance(loadBalancerType, extLoadBalancerName), serializerType, unresolvedSocketAddress);
                }else{
                    return new DefaultRoundDispatcher(
                            client,
                            LoadBalancerFactory.getInstance(loadBalancerType, extLoadBalancerName), serializerType);
                }

            case BROADCAST:
                return new DefaultBroadcastDispatcher(client, serializerType);
            default:
                throw reject("dispatchType: " + dispatchType);
        }
    }

    private static UnsupportedOperationException reject(String message) {
        return new UnsupportedOperationException(message);
    }
}

package org.jupiter.rpc.consumer.dispatcher;

import org.jupiter.common.util.SystemClock;
import org.jupiter.common.util.internal.logging.InternalLogger;
import org.jupiter.common.util.internal.logging.InternalLoggerFactory;
import org.jupiter.rpc.DispatchType;
import org.jupiter.rpc.JClient;
import org.jupiter.rpc.JRequest;
import org.jupiter.rpc.consumer.future.InvokeFuture;
import org.jupiter.rpc.load.balance.LoadBalancer;
import org.jupiter.rpc.model.metadata.MessageWrapper;
import org.jupiter.rpc.model.metadata.ServiceMetadata;
import org.jupiter.serialization.Serializer;
import org.jupiter.serialization.SerializerType;
import org.jupiter.serialization.io.OutputBuf;
import org.jupiter.transport.*;
import org.jupiter.transport.channel.CopyOnWriteGroupList;
import org.jupiter.transport.channel.JChannel;
import org.jupiter.transport.channel.JChannelGroup;

/**
 * 单播方式派发消息.
 *
 * jupiter
 * org.jupiter.rpc.consumer.dispatcher
 *
 * @author wangjp
 */
public class CiccOmsDispatcher extends AbstractDispatcher {
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(CiccOmsDispatcher.class);

    private UnresolvedAddress unresolvedAddress;
    private final JClient client;
    private final LoadBalancer loadBalancer;                    // 软负载均衡

    public CiccOmsDispatcher(
            JClient client, LoadBalancer loadBalancer, SerializerType serializerType, UnresolvedAddress unresolvedAddress) {
        super(client, loadBalancer, serializerType);
        this.unresolvedAddress = unresolvedAddress;
        this.client = client;
        this.loadBalancer = loadBalancer;
    }

    @Override
    public  InvokeFuture dispatch(JRequest request, Class returnType) {
        // stack copy
        final Serializer _serializer = serializer();
        final MessageWrapper message = request.message();

        // 通过指定ip获取一个channel
        JChannel channel = select(message.getMetadata());

        byte s_code = _serializer.code();
        // 在业务线程中序列化, 减轻IO线程负担
        if (CodecConfig.isCodecLowCopy()) {
            OutputBuf outputBuf =
                    _serializer.writeObject(channel.allocOutputBuf(), message);
            request.outputBuf(s_code, outputBuf);
        } else {
            byte[] bytes = _serializer.writeObject(message);
            request.bytes(s_code, bytes);
        }

        return write(channel, request, returnType, DispatchType.ROUND);
    }

    @Override
    protected JChannel select(ServiceMetadata metadata) {
        JChannelGroup group = null;
        CopyOnWriteGroupList groups = client
                .connector()
                .directory(metadata);
        JChannelGroup[] elements = groups.getSnapshot();
        for (int i = 0; i < elements.length; i++) {
            UnresolvedAddress eleUnresolvedAddress = elements[i].remoteAddress();
            if (eleUnresolvedAddress.equals(unresolvedAddress)) {
                group = elements[i];
                break;
            }
        }
        JChannel channel;
        if (group != null) {
            if (group.isAvailable()) {
                return group.next();
            }

            // to the deadline (no available channel), the time exceeded the predetermined limit
            long deadline = group.deadlineMillis();
            if (deadline > 0 && SystemClock.millisClock().now() > deadline) {
                boolean removed = groups.remove(group);
                if (removed) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Removed channel group: {} in directory: {} on [select].",
                                group, metadata.directoryString());
                    }
                }
            }
        } else {
            // for 3 seconds, expired not wait
            if (!client.awaitConnections(metadata, 3000)) {
                throw new IllegalStateException("No connections");
            }
        }
//        //以下代码用于处理当本次请求的服务失效时,获取一个有效的服务进行请求处理。
//        //在这个项目中,每个服务具有唯一性,所以一下代码不适用于该项目
//        JChannelGroup[] snapshot = groups.getSnapshot();
//        for (JChannelGroup g : snapshot) {
//            if (g.isAvailable()) {
//                return g.next();
//            }
//        }

        throw new IllegalStateException("No channel");
    }
}

你可能感兴趣的:(java学习)