sofa-bolt源码解读之处理器

官方文档请参考:https://www.sofastack.tech/projects/sofa-bolt/sofa-bolt-handbook/

简书优质博文:https://www.jianshu.com/p/f2b8a2099323

目录

两类处理器

用户请求处理器

同步请求处理器抽象类SyncUserProcessor

异步请求处理器抽象类AsyncUserProcessor

连接事件处理器

ConnectionEventProcessor连接事件接口类

CONNECTEventProcessor连接事件处理器

DISCONNECTEventProcessor断连事件处理器


两类处理器

sofa-bolt提供两种类型的处理器:用户请求处理器连接事件处理器

用户请求处理器主要用来对请求数据进行响应处理,比如服务端接受到请求后给与客户端一个特定的响应消息。

连接事件处理器主要用来对连接,关闭,连接异常等事件进行监听,从而进行一些相关操作。

用户请求处理器

提供了两种用户请求处理器,SyncUserProcessor AsyncUserProcessor。 二者的区别在于,前者需要在当前处理线程以return返回值的形式返回处理结果;而后者,有一个 AsyncContext 存根,可以在当前线程,也可以在异步线程,调用 sendResponse 方法返回处理结果。

继承关系类图如下:

示例可参考如下两个类:

同步请求处理器抽象类SyncUserProcessor

/**
 * 继承这个类去处理用户用同步的方式定义的请求
 * Extends this to process user defined request in SYNC way.<br>
 * 如果你想用异步的方式处理请求,请拓展AsyncUserProcessor处理器
 * If you want process request in ASYNC way, please extends {@link AsyncUserProcessor}.
 *
 * @author xiaomin.cxm
 * @version $Id: SyncUserProcessor.java, v 0.1 May 19, 2016 2:47:21 PM xiaomin.cxm Exp $
 */
public abstract class SyncUserProcessor<T> extends AbstractUserProcessor<T> {
    /**
     * @see com.alipay.remoting.rpc.protocol.UserProcessor#handleRequest(com.alipay.remoting.BizContext, java.lang.Object)
     */
    @Override
    public abstract Object handleRequest(BizContext bizCtx, T request) throws Exception;

    /**
     * unsupported here!
     *
     * @see com.alipay.remoting.rpc.protocol.UserProcessor#handleRequest(com.alipay.remoting.BizContext, com.alipay.remoting.AsyncContext, java.lang.Object)
     */
    @Override
    public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, T request) {
        throw new UnsupportedOperationException(
            "ASYNC handle request is unsupported in SyncUserProcessor!");
    }

    /**
     * @see com.alipay.remoting.rpc.protocol.UserProcessor#interest()
     */
    @Override
    public abstract String interest();
}

可以看到这个抽象类中定义了两个handleRequest()方法,一个有返回值的和一个没有返回值的,而没有返回值的那个方法直接给了一个异常处理,提示不支持异步请求。所以对于用户使用同步方式的请求,就需要实现有返回值的handleRequest(),具体事例请参考官方示例:自定义用户同步处理器

以下是截取的复写handleRequest()的部分代码,我们可以看到return了一个默认的服务端响应。

    // ~~~ override methods

    @Override
    public Object handleRequest(BizContext bizCtx, RequestBody request) throws Exception {
        logger.warn("Request received:" + request + ", timeout:" + bizCtx.getClientTimeout()
                    + ", arriveTimestamp:" + bizCtx.getArriveTimestamp());
        if (bizCtx.isRequestTimeout()) {
            String errMsg = "Stop process in server biz thread, already timeout!";
            processTimes(request);
            logger.warn(errMsg);
            throw new Exception(errMsg);
        }

        this.remoteAddr = bizCtx.getRemoteAddress();

        //test biz context get connection
        Assert.assertNotNull(bizCtx.getConnection());
        Assert.assertTrue(bizCtx.getConnection().isFine());

        Long waittime = (Long) bizCtx.getInvokeContext().get(InvokeContext.BOLT_PROCESS_WAIT_TIME);
        Assert.assertNotNull(waittime);
        if (logger.isInfoEnabled()) {
            logger.info("Server User processor process wait time {}", waittime);
        }

        latch.countDown();
        logger.warn("Server User processor say, remote address is [" + this.remoteAddr + "].");
        Assert.assertEquals(RequestBody.class, request.getClass());
        processTimes(request);
        if (!delaySwitch) {
            return RequestBody.DEFAULT_SERVER_RETURN_STR;
        }
        try {
            Thread.sleep(delayMs);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return RequestBody.DEFAULT_SERVER_RETURN_STR;
    }

查看源码我们可以看到这里使用了适配器模式

其中 AbstractUserProcessor  可以看做是接口的适配器(为接口的每一个方法做了默认实现,使得最底层的四个抽象仅仅实现自己需要实现的方法就可以),所以个人更倾向于取名为 UserProcessorAdapter

异步请求处理器抽象类AsyncUserProcessor

/**
 * Extends this to process user defined request in ASYNC way.<br>
 * If you want process request in SYNC way, please extends {@link SyncUserProcessor}.
 *
 * @author xiaomin.cxm
 * @version $Id: AsyncUserProcessor.java, v 0.1 May 16, 2016 8:18:03 PM xiaomin.cxm Exp $
 */
public abstract class AsyncUserProcessor<T> extends AbstractUserProcessor<T> {
    /**
     * unsupported here!
     *
     * @see com.alipay.remoting.rpc.protocol.UserProcessor#handleRequest(com.alipay.remoting.BizContext, java.lang.Object)
     */
    @Override
    public Object handleRequest(BizContext bizCtx, T request) throws Exception {
        throw new UnsupportedOperationException(
            "SYNC handle request is unsupported in AsyncUserProcessor!");
    }

    /**
     * @see com.alipay.remoting.rpc.protocol.UserProcessor#handleRequest(com.alipay.remoting.BizContext, com.alipay.remoting.AsyncContext, java.lang.Object)
     */
    @Override
    public abstract void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, T request);

    /**
     * @see com.alipay.remoting.rpc.protocol.UserProcessor#interest()
     */
    @Override
    public abstract String interest();
}

可以看到这个抽象类中定义了两个handleRequest()方法,一个有返回值的和一个没有返回值的,而有返回值的那个方法直接给了一个异常处理,提示不支持同步请求。所以对于用户使用异步方式的请求,就需要实现没有返回值的handleRequest(),具体事例请参考官方示例:自定义用户异步处理器

以下是截取的复写handleRequest()的部分代码,我们可以看到有一个 AsyncContext 存根,可以在当前线程,也可以在异步线程,在异步线程,调用 sendResponse 方法返回处理结果。

    @Override
    public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, RequestBody request) {
        this.asyncExecutor.execute(new InnerTask(bizCtx, asyncCtx, request));
    }

    class InnerTask implements Runnable {
        private BizContext   bizCtx;
        private AsyncContext asyncCtx;
        private RequestBody  request;

        public InnerTask(BizContext bizCtx, AsyncContext asyncCtx, RequestBody request) {
            this.bizCtx = bizCtx;
            this.asyncCtx = asyncCtx;
            this.request = request;
        }

        public void run() {
            logger.warn("Request received:" + request);
            remoteAddr = bizCtx.getRemoteAddress();
            latch.countDown();
            logger.warn("Server User processor say, remote address is [" + remoteAddr + "].");
            Assert.assertEquals(RequestBody.class, request.getClass());
            processTimes(request);
            if (isException) {
                this.asyncCtx.sendResponse(new IllegalArgumentException("Exception test"));
            } else if (isNull) {
                this.asyncCtx.sendResponse(null);
            } else {
                if (!delaySwitch) {
                    this.asyncCtx.sendResponse(RequestBody.DEFAULT_SERVER_RETURN_STR);
                    return;
                }
                try {
                    Thread.sleep(delayMs);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.asyncCtx.sendResponse(RequestBody.DEFAULT_SERVER_RETURN_STR);
            }
        }
    }

连接事件处理器

提供了两种事件监听,建连事件(ConnectionEventType.CONNECT)与断连事件(ConnectionEventType.CLOSE),用户可以创建自己的事件处理器,并注册到客户端或者服务端。客户端与服务端,都可以监听到各自的建连与断连事件。

看一下如下枚举类,里面包含四种事件,连接,连接失败,关闭,异常。

/**
 * Event triggered by connection state.
 * 
 * @author jiangping
 * @version $Id: ConnectionEventType.java, v 0.1 Mar 4, 2016 8:03:27 PM tao Exp $
 */
public enum ConnectionEventType {
    CONNECT, CONNECT_FAILED, CLOSE, EXCEPTION;
}

ConnectionEventProcessor连接事件接口类

/**
 * Process connection events.
 * @author jiangping
 * @version $Id: ConnectionEventProcessor.java, v 0.1 Mar 5, 2016 11:01:07 AM tao Exp $
 */
public interface ConnectionEventProcessor {
    /**
     * Process event.<br>
     * 
     * @param remoteAddress remoting connection
     * @param connection Connection
     */
    void onEvent(String remoteAddress, Connection connection);
}

CONNECTEventProcessor连接事件处理器

如下是连接事件处理器源码

/**
 * ConnectionEventProcessor for ConnectionEventType.CONNECT
 * 
 * @author xiaomin.cxm
 * @version $Id: CONNECTEventProcessor.java, v 0.1 Apr 8, 2016 10:58:48 AM xiaomin.cxm Exp $
 */
public class CONNECTEventProcessor implements ConnectionEventProcessor {

    private AtomicBoolean  connected    = new AtomicBoolean();
    private AtomicInteger  connectTimes = new AtomicInteger();
    private Connection     connection;
    private String         remoteAddr;
    private CountDownLatch latch        = new CountDownLatch(1);

    @Override
    public void onEvent(String remoteAddr, Connection conn) {
        Assert.assertNotNull(remoteAddr);
        doCheckConnection(conn);
        this.remoteAddr = remoteAddr;
        this.connection = conn;
        connected.set(true);
        connectTimes.incrementAndGet();
        latch.countDown();
    }

    /**
     * do check connection
     * @param conn
     */
    private void doCheckConnection(Connection conn) {
        Assert.assertNotNull(conn);
        Assert.assertNotNull(conn.getPoolKeys());
        Assert.assertTrue(conn.getPoolKeys().size() > 0);
        Assert.assertNotNull(conn.getChannel());
        Assert.assertNotNull(conn.getUrl());
        Assert.assertNotNull(conn.getChannel().attr(Connection.CONNECTION).get());
    }

    public boolean isConnected() throws InterruptedException {
        latch.await();
        return this.connected.get();
    }

    public int getConnectTimes() throws InterruptedException {
        latch.await();
        return this.connectTimes.get();
    }

    public Connection getConnection() throws InterruptedException {
        latch.await();
        return this.connection;
    }

    public String getRemoteAddr() throws InterruptedException {
        latch.await();
        return this.remoteAddr;
    }

    public void reset() {
        this.connectTimes.set(0);
        this.connected.set(false);
        this.connection = null;
    }
}

可以看到实现了onEvent()方法,主要是拿到了当前的连接和远程访问的地址,然后给连接状态设为true。另外还提供了 是否连接、获取连接次数、获取连接、获取远程访问的地址等方法。

那么有一个疑问,onEvent()是在什么时候调用的呢?

我们来看下客户端启动的代码,如下

    @Override
    public void startup() throws LifeCycleException {
        super.startup();

        for (UserProcessor<?> userProcessor : userProcessors.values()) {
            if (!userProcessor.isStarted()) {
                userProcessor.startup();
            }
        }

        if (this.addressParser == null) {
            this.addressParser = new RpcAddressParser();
        }

        ConnectionSelectStrategy connectionSelectStrategy = option(BoltGenericOption.CONNECTION_SELECT_STRATEGY);
        if (connectionSelectStrategy == null) {
            connectionSelectStrategy = new RandomSelectStrategy(switches());
        }
        this.connectionManager = new DefaultClientConnectionManager(connectionSelectStrategy,
            new RpcConnectionFactory(userProcessors, this), connectionEventHandler,
            connectionEventListener, switches()); //创建默认的连接管理器
        this.connectionManager.setAddressParser(this.addressParser);
        this.connectionManager.startup();
        this.rpcRemoting = new RpcClientRemoting(new RpcCommandFactory(), this.addressParser,
            this.connectionManager);
        this.taskScanner.add(this.connectionManager);
        this.taskScanner.startup();

        if (switches().isOn(GlobalSwitch.CONN_MONITOR_SWITCH)) {
            if (monitorStrategy == null) {
                connectionMonitor = new DefaultConnectionMonitor(new ScheduledDisconnectStrategy(),
                    this.connectionManager);
            } else {
                connectionMonitor = new DefaultConnectionMonitor(monitorStrategy,
                    this.connectionManager);
            }
            connectionMonitor.startup();
            logger.warn("Switch on connection monitor");
        }
        if (switches().isOn(GlobalSwitch.CONN_RECONNECT_SWITCH)) {
            reconnectManager = new ReconnectManager(connectionManager);
            reconnectManager.startup();

            connectionEventHandler.setReconnector(reconnectManager);
            logger.warn("Switch on reconnect manager");
        }
    }

我们看到在初始化connectionManager时传了一个connectionEventListener监听器

DISCONNECTEventProcessor断连事件处理器

这个处理器原理与上大同小异,就不做过多介绍了。

猜你喜欢

转载自blog.csdn.net/qq_34050399/article/details/115232386