sentinel-tansport-SPI-CommandSPI

说明

我们引入以下

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
     <version>1.8.6</version>
</dependency>

通过初始化com.alibaba.csp.sentinel.init.InitExecutor#doInit 之后就可以通过sentinel暴露的端口调用相关api

如果使用了alibaba-starter-sentinel则不需要手动调用因为com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration#init在这里面执行了自动调用

他是如何实现呢

<1>

com.alibaba.csp.sentinel.init.InitExecutor#doInit

  public static void doInit() {
        //原子性set和判断是否已经初始化
        if (!initialized.compareAndSet(false, true)) {
            return;
        }
        try {
            //SPI获取InitFunc
            ServiceLoader<InitFunc> loader = ServiceLoaderUtil.getServiceLoader(InitFunc.class);
            List<OrderWrapper> initList = new ArrayList<OrderWrapper>();
            for (InitFunc initFunc : loader) {
                RecordLog.info("[InitExecutor] Found init func: " + initFunc.getClass().getCanonicalName());
                insertSorted(initList, initFunc);
            }
            for (OrderWrapper w : initList) {
                //<2>执行初始化 针对commnad是com.alibaba.csp.sentinel.transport.init.CommandCenterInitFunc#init
                w.func.init();
                RecordLog.info(String.format("[InitExecutor] Executing %s with order %d",
                    w.func.getClass().getCanonicalName(), w.order));
            }
        } catch (Exception ex) {
            RecordLog.warn("[InitExecutor] WARN: Initialization failed", ex);
            ex.printStackTrace();
        } catch (Error error) {
            RecordLog.warn("[InitExecutor] ERROR: Initialization failed with fatal error", error);
            error.printStackTrace();
        }
    }

<2>

@InitOrder(-1)
public class CommandCenterInitFunc implements InitFunc {

    @Override
    public void init() throws Exception {
        //这里也是SPI的方式获取CommandCenter 我们可以自定义,默认是 com.alibaba.csp.sentinel.transport.command.SimpleHttpCommandCenter
        CommandCenter commandCenter = CommandCenterProvider.getCommandCenter();

        if (commandCenter == null) {
            RecordLog.warn("[CommandCenterInitFunc] Cannot resolve CommandCenter");
            return;
        }
        //<3>执行command的初始化内部也是SPI的方式,我们可以动态新增
        commandCenter.beforeStart();
//<6>开启http service commandCenter.start(); RecordLog.info(
"[CommandCenterInit] Starting command center: " + commandCenter.getClass().getCanonicalName()); } }

<3>

com.alibaba.csp.sentinel.transport.command.SimpleHttpCommandCenter#beforeStart

    public void beforeStart() throws Exception {
        //<4>SPI的方式获取
        Map<String, CommandHandler> handlers = CommandHandlerProvider.getInstance().namedHandlers();
        //<5>注册command 
        registerCommands(handlers);
    }

<4>

com.alibaba.csp.sentinel.command.CommandHandlerProvider#namedHandlers

public class CommandHandlerProvider implements Iterable<CommandHandler> {

    //SPI的方式获取CommandHandler
    private final ServiceLoader<CommandHandler> serviceLoader = ServiceLoaderUtil.getServiceLoader(
        CommandHandler.class);

    /**
     * Get all command handlers annotated with {@link CommandMapping} with command name.
     *
     * @return list of all named command handlers
     */
    public Map<String, CommandHandler> namedHandlers() {
        Map<String, CommandHandler> map = new HashMap<String, CommandHandler>();
        for (CommandHandler handler : serviceLoader) {
            String name = parseCommandName(handler);
            if (!StringUtil.isEmpty(name)) {
                map.put(name, handler);
            }
        }
        return map;
    }

    private String parseCommandName(CommandHandler handler) {
        //需要打了CommandMapping注解 name为url映射
        CommandMapping commandMapping = handler.getClass().getAnnotation(CommandMapping.class);
        if (commandMapping != null) {
            return commandMapping.name();
        } else {
            return null;
        }
    }
  ......

}

<5>

注册到static变量

com.alibaba.csp.sentinel.transport.command.SimpleHttpCommandCenter#registerCommands

  private static final Map<String, CommandHandler> handlerMap = new ConcurrentHashMap();
 public static void registerCommand(String commandName, CommandHandler handler) {
        if (!StringUtil.isEmpty(commandName)) {
            if (handlerMap.containsKey(commandName)) {
                CommandCenterLog.warn("Register failed (duplicate command): " + commandName, new Object[0]);
            } else {
                handlerMap.put(commandName, handler);
            }
        }
    }

<6>

com.alibaba.csp.sentinel.transport.command.SimpleHttpCommandCenter#start

  public void start() throws Exception {
         //获取cpu核数 作为请求处理线程数
        int nThreads = Runtime.getRuntime().availableProcessors();
        //初始化http请求处理的线程池
        this.bizExecutor = new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(10), new NamedThreadFactory("sentinel-command-center-service-executor"), new RejectedExecutionHandler() {
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                CommandCenterLog.info("EventTask rejected", new Object[0]);
                throw new RejectedExecutionException();
            }
        });
        //处理认为
        Runnable serverInitTask = new Runnable() {
            int port;

            {
                try {
                    //获取配置的端口信息
                    this.port = Integer.parseInt(TransportConfig.getPort());
                } catch (Exception var3) {
                    //出现异常8719
                    this.port = 8719;
                }

            }

            public void run() {
                boolean success = false;
                //初始化ServerSocket 内部会通过port进行监听,如果冲突则自动+1往上找
                ServerSocket serverSocket = SimpleHttpCommandCenter.getServerSocketFromBasePort(this.port);
                if (serverSocket != null) {
                    CommandCenterLog.info("[CommandCenter] Begin listening at port " + serverSocket.getLocalPort(), new Object[0]);
                    SimpleHttpCommandCenter.this.socketReference = serverSocket;
                    //<7>开启监听http线程处理器 监听器为ServerThread 
                    SimpleHttpCommandCenter.this.executor.submit(SimpleHttpCommandCenter.this.new ServerThread(serverSocket));
                    success = true;
                    this.port = serverSocket.getLocalPort();
                } else {
                    CommandCenterLog.info("[CommandCenter] chooses port fail, http command center will not work", new Object[0]);
                }

                if (!success) {
                    this.port = -1;
                }

                TransportConfig.setRuntimePort(this.port);
                SimpleHttpCommandCenter.this.executor.shutdown();
            }
        };
        (new Thread(serverInitTask)).start();

<7>

com.alibaba.csp.sentinel.transport.command.SimpleHttpCommandCenter.ServerThread#run

 public void run() {
            while(true) {
                Socket socket = null;

                try {
                    //监听请求
                    socket = this.serverSocket.accept();
                    SimpleHttpCommandCenter.this.setSocketSoTimeout(socket);
                    HttpEventTask eventTask = new HttpEventTask(socket);
                    //<8>监听到请求交给HttpEventTask 处理
                    SimpleHttpCommandCenter.this.bizExecutor.submit(eventTask);
                } catch (Exception var6) {
                    CommandCenterLog.info("Server error", var6);
                    if (socket != null) {
                        try {
                            socket.close();
                        } catch (Exception var5) {
                            CommandCenterLog.info("Error when closing an opened socket", var5);
                        }
                    }

                    try {
                        Thread.sleep(10L);
                    } catch (InterruptedException var4) {
                        return;
                    }
                }
            }
        }

com.alibaba.csp.sentinel.transport.command.http.HttpEventTask#run

    public void run() {
        if (this.socket != null) {
            PrintWriter printWriter = null;
            InputStream inputStream = null;

            try {
                long start = System.currentTimeMillis();
                inputStream = new BufferedInputStream(this.socket.getInputStream());
                OutputStream outputStream = this.socket.getOutputStream();
                printWriter = new PrintWriter(new OutputStreamWriter(outputStream, Charset.forName(SentinelConfig.charset())));
                String firstLine = readLine(inputStream);
                CommandCenterLog.info("[SimpleHttpCommandCenter] Socket income: " + firstLine + ", addr: " + this.socket.getInetAddress(), new Object[0]);
                CommandRequest request = processQueryString(firstLine);
                if (firstLine.length() > 4 && StringUtil.equalsIgnoreCase("POST", firstLine.substring(0, 4))) {
                    processPostRequest(inputStream, request);
                }

                String commandName = HttpCommandUtils.getTarget(request);
                if (StringUtil.isBlank(commandName)) {
                    this.writeResponse(printWriter, StatusCode.BAD_REQUEST, "Invalid command");
                    return;
                }

                //核心代码 获取对应的Handler就是前面SPI初始化的
                CommandHandler<?> commandHandler = SimpleHttpCommandCenter.getHandler(commandName);
                if (commandHandler != null) {
                    CommandResponse<?> response = commandHandler.handle(request);
                    this.handleResponse(response, printWriter);
                } else {
                    this.writeResponse(printWriter, StatusCode.BAD_REQUEST, "Unknown command `" + commandName + '`');
                }

                long cost = System.currentTimeMillis() - start;
                CommandCenterLog.info("[SimpleHttpCommandCenter] Deal a socket task: " + firstLine + ", address: " + this.socket.getInetAddress() + ", time cost: " + cost + " ms", new Object[0]);
            } catch (RequestException var18) {
                this.writeResponse(printWriter, var18.getStatusCode(), var18.getMessage());
            } catch (Throwable var19) {
                Throwable e = var19;
                CommandCenterLog.warn("[SimpleHttpCommandCenter] CommandCenter error", var19);

                try {
                    if (printWriter != null) {
                        String errorMessage = "Command server error";
                        e.printStackTrace();
                        if (!this.writtenHead) {
                            this.writeResponse(printWriter, StatusCode.INTERNAL_SERVER_ERROR, errorMessage);
                        } else {
                            printWriter.println(errorMessage);
                        }

                        printWriter.flush();
                    }
                } catch (Exception var17) {
                    CommandCenterLog.warn("Failed to write error response", var17);
                }
            } finally {
                this.closeResource(inputStream);
                this.closeResource(printWriter);
                this.closeResource(this.socket);
            }

        }
    }

 

 

posted @ 2024-09-29 10:21  意犹未尽  阅读(7)  评论(0编辑  收藏  举报