手写一个简单的网关-自定义配置文件与链式构造处理器

通过自定义配置文件可以实现定义不同处理器的执行顺序,不同处理器的具体执行策略,具体执行策略的不同参数。这里通过io流,策略者模式工厂模式来实现。配置文件的格式如下。

#自定义配置文件规则 每个:之前表示对应的不同处理器 enable表示是否启用 policy表示具体使用的策略
#还有一些表示具体的策略参数比如blackTime表示防刷处理器的拉黑时间 maxRequest表示限流处理器的允许最大请求数
#每行前面如果加了#表示注释
#如果想调整某个处理器的顺序就将该处理器的位置上移或者下移 上面的先执行 下面的后执行


auth:enable=true &policy=jwt
flush:enable=true & policy=black & blackTime=3600000
limit:enable=true & policy=token & maxRequest=20000 & capacity=10000 & rate=10000
router:enable=true & policy=config & loadBalance=hash
routerMap:/api=localhost-1249
& /api/user=localhost-7070
           & /api/user=localhost-6060 &/api/home=localhost-1111
grayRouterMap:/api/user=graylocalhost:8080
secretMap:/api/user=secret1 & /api/home=secret2

来看具体的配置加载类

package server;

import Util.ObjectUtil;

import java.io.*;
import java.util.*;

public class ConfigReader {

    //TODO 动态读取
    //private static String FILE_PATH =new File("config.txt").getAbsolutePath();
    public static String FILE_PATH = "D:\\project\\IdeaProjects\\EasyGateway\\src\\main\\resources\\config.txt";
    /**
     * 采用LinkedHashMap保证插入顺序 这样之后如果要修改处理器的执行顺序只需要修该配置文件的顺序就可以
     */
    private static Map<String, Map<String, String>> configMap = new LinkedHashMap<>();

    private void loadConfig(String filePath) {
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            String currentSection = null;
            while ((line = br.readLine()) != null) {
                line = line.trim();
                if (line.isEmpty() || line.startsWith("#")) {
                    continue;
                }
                if (line.contains(":")) {
                    String[] section = line.split(":");
                    currentSection = section[0].trim();
                    line = section[1].trim();
                    configMap.put(currentSection, new HashMap<>());
                }
                if (currentSection != null) {
                    String[] pairs = line.split("&");
                    for (String pair : pairs) {
                        String[] keyValue = pair.split("=");
                        if (keyValue.length == 2) {
                            String key = keyValue[0].trim();
                            String value = keyValue[1].trim();
                            configMap.get(currentSection).compute(key, (k, v) -> (v == null ? value : v + "&" + value));
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        loadConfig(FILE_PATH);
        ProcessorsBuilder.initProcessor(configMap);
    }

    public static Map<String, Map<String, String>> getConfigMap() {
        return configMap;
    }
    public static Map<String, List<String>>getRouterMap(String name){
        Map<String, String> routerMap = configMap.get(name);
        Map<String,List<String>>res=new HashMap<>();
        if(routerMap!=null){
            for (Map.Entry<String, String> entry : routerMap.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue().replace("-", ":");
                String[] split = value.split("&");
                List<String> strings = Arrays.asList(split);
                res.put(key, strings);
            }
        }

        return res;
    }
    public static Map<String, String>getSecretMap(){
       return configMap.get("secretMap");
    }
}

configmap中存储的就是配置文件中的所有内容,key为对应的配置比如每个处理器,value是一个map存储的就是每个配置的各种属性。这里面的getRoutermap可以获取不同前缀对应的各种主机ip,比如你可以在配置文件中配置/api/user前缀对应两个路由主机a,b,之后在路由处理器中就会将该前缀去掉同时根据负载均衡策略选择一个路由主机进行请求。它里面的name参数可以选择灰度路由map和普通路由map。这个后面会实现。

来看处理器链式构造

package server;



import processors.EmptyProcessor;
import processors.Processor;
import processors.ProcessorFactory;
import processors.auth.JwtAuthProcessor;
import processors.flush.BlackFlushProcessor;
import processors.limit.CountLimit;
import processors.limit.LeakyBucketLimit;
import processors.limit.TokenBucketLimit;
import processors.router.ConfigRouter;


import java.util.HashMap;
import java.util.Map;

import java.util.function.Function;

/**
 * 构造处理器
 */
public class ProcessorsBuilder {
    private static Processor firstProcessor;

    private static Map<String, Map<String, String>> processorMap = new HashMap<>();
    private static Map<String,String> defaultProcessor = new HashMap<>();
    private static final Map<String, Function<Map<String, String>, Processor>> processorCreateMap = new HashMap<>();

    /**
     * 策略者模式加工厂模式 每个处理器有多个不同的实现 将不同的处理器的生产方法注册到map中后续生产只需要拿到需要生产的处理器的类名 直接调用生产方法就可以生产
     * 生产方法定义在处理器工厂中
     */
    static {
        processorCreateMap.put(BlackFlushProcessor.class.getName(), ProcessorFactory::createBlackFlushProcessor);
        processorCreateMap.put(CountLimit.class.getName(), ProcessorFactory::createCountLimit);
        processorCreateMap.put(LeakyBucketLimit.class.getName(), ProcessorFactory::createLeakyBucketLimit);
        processorCreateMap.put(TokenBucketLimit.class.getName(), ProcessorFactory::createTokenBucketLimit);
        processorCreateMap.put(ConfigRouter.class.getName(), ProcessorFactory::createConfigRouter);
    }



    //加载将每种处理器支持的不同种类处理器
    static {
        Map<String,String>authMap=new HashMap<>();
        authMap.put("jwt", JwtAuthProcessor.class.getName());
        defaultProcessor.put("auth", JwtAuthProcessor.class.getName());

        Map<String,String>flushMap=new HashMap<>();
        flushMap.put("black", BlackFlushProcessor.class.getName());
        defaultProcessor.put("flush", BlackFlushProcessor.class.getName());

        Map<String,String>limitMap=new HashMap<>();
        limitMap.put("count", CountLimit.class.getName());
        limitMap.put("leaky", LeakyBucketLimit.class.getName());
        limitMap.put("token", TokenBucketLimit.class.getName());
        defaultProcessor.put("limit", CountLimit.class.getName());

        Map<String,String>routerMap=new HashMap<>();
        routerMap.put("config", ConfigRouter.class.getName());
        defaultProcessor.put("router", ConfigRouter.class.getName());


        processorMap.put("auth",authMap);
        processorMap.put("flush",flushMap);
        processorMap.put("limit",limitMap);
        processorMap.put("router",routerMap);
        firstProcessor = new EmptyProcessor();
    }

    public static void initProcessor(Map<String,Map<String,String>> configMap) {
        Processor processor = getProcessor();
        for (Map.Entry<String, Map<String, String>> entry : configMap.entrySet()) {
            String key = entry.getKey();
            if(processorMap.containsKey(key)){
                Processor next = createProcessor(key, entry.getValue());
                processor.setNext(next);
                processor = next;
            }
        }
    }

    private static Processor createProcessor(String type, Map<String, String> property)  {
        Map<String, String> typeMap = processorMap.get(type);
        if (typeMap == null) {
            throw new RuntimeException("processor type " + type + " not found");
        }
        String enable = property.getOrDefault("enable", "true");
        if (!"true".equals(enable)) {
            return new EmptyProcessor();
        }
        String className = typeMap.getOrDefault(property.get("policy"), defaultProcessor.get(type));
        if(processorCreateMap.containsKey(className)){
            return processorCreateMap.get(className).apply(property);
        }else{
            try {
               return ProcessorFactory.createEmptyProperProcessor(className);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

    }



    public static Processor getProcessor() {
        return firstProcessor;
    }

}

工厂类

package processors;

import processors.flush.BlackFlushProcessor;
import processors.limit.CountLimit;
import processors.limit.LeakyBucketLimit;
import processors.limit.TokenBucketLimit;
import processors.router.ConfigRouter;
import processors.router.loadbalance.HashLoadBalance;
import processors.router.loadbalance.LoadBalance;
import processors.router.loadbalance.PollingLoadBalance;
import processors.router.loadbalance.RandomLoadBalance;


import java.util.Map;

/**
 * 处理器工厂 生产需要不同参数的处理器
 */
public class ProcessorFactory {

    public static Processor createBlackFlushProcessor(Map<String, String> property) {
        String blackTime = property.getOrDefault("blackTime", "3600000");
        String maxRequest = property.getOrDefault("maxRequest", "1000");
        return new BlackFlushProcessor(Integer.parseInt(maxRequest), Long.parseLong(blackTime));
    }
    public static Processor createCountLimit(Map<String, String> property) {
        String maxRequest = property.getOrDefault("maxRequest", "1000");
        return new CountLimit(Integer.parseInt(maxRequest));
    }

    public static Processor createLeakyBucketLimit(Map<String, String> property) {
        String capacity = property.getOrDefault("capacity", "1000");
        String rate = property.getOrDefault("rate", "100");
        return new LeakyBucketLimit(Integer.parseInt(capacity), Integer.parseInt(rate));
    }

    public static Processor createTokenBucketLimit(Map<String, String> property) {
        String capacity = property.getOrDefault("capacity", "1000");
        String rate = property.getOrDefault("rate", "100");
        return new TokenBucketLimit(Integer.parseInt(capacity), Integer.parseInt(rate));
    }
    public static Processor createEmptyProperProcessor(String className) throws Exception {
        Class<?> aClass = Class.forName(className);
        Processor o = (Processor)aClass.getConstructor().newInstance();
        return o;
    }
    public static Processor createConfigRouter(Map<String, String> property)  {
        String loadBalance = property.getOrDefault("loadBalance", "hash");
        LoadBalance lb = null;
        switch (loadBalance) {
            case "hash": lb=new HashLoadBalance();break;
            case "polling":lb=new PollingLoadBalance();break;
            case "random":lb=new RandomLoadBalance();break;
        }
        return new ConfigRouter(lb);
    }

}

首先在processorCreateMap中会注册一些需要进行参数配置的具体策略的创建方法,之后会将不同处理器支持的不同策略注册到processorMap,同时将默认策略注册到defaultProcessor中。这里链式构造的时候采用了一个EmptyProcessor,可以作为处理器链式的头节点和空节点,这样如果配置文件没有配置处理器和不启用该处理器的时候就不用作特殊处理起到一个占位的作用。

package processors;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;

/**
 * 空处理器 用于作为处理器责任链模式的头节点
 */
public class EmptyProcessor implements Processor {
    private Processor nextProcessor;
    @Override
    public void process(ChannelHandlerContext ctx, FullHttpRequest request) {
        if(nextProcessor!=null){
            nextProcessor.process(ctx, request);
        }
    }

    @Override
    public void setNext(Processor processor) {
        this.nextProcessor = processor;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值