如何处理route的数据结构 ,如何构建route

来源:互联网 发布:linux清除文件夹内容 编辑:程序博客网 时间:2024/05/22 10:38

如何处理route的数据结构 ,如何构建route

route是一个在web程序中扮演很重要的角色,我们的uri其实就是一个路由,通过路由我们可以区分不同的请求,然后分派到具体的类中去执行响应具体的操作,那么怎么知道当前的uri到底是请求的哪个呢,这个就涉及到了route的数据结构的问题,慢慢的去体会他的无穷的奥妙。
Route的数据结构

public class Route {    /**     * HTTP Request Method     */    private HttpMethod httpMethod;    /**     * Route path     */    private String path;    /**     * Logical controller object     */    private Object target;    /**     * Controller Class Type     */    private Class<?> targetType;    /**     * Implementation logic controller method     */    private Method action;    public Route() {    }    public Route(HttpMethod httpMethod, String path, Object target, Class<?> targetType, Method action) {        super();        this.httpMethod = httpMethod;        this.path = Path.fixPath(path);        this.target = target;        this.targetType = targetType;        this.action = action;    }    public HttpMethod getHttpMethod() {        return httpMethod;    }    public String getPath() {        return path;    }    public void setPath(String path) {        this.path = path;    }    public Object getTarget() {        return target;    }    public void setTarget(Object target) {        this.target = target;    }    public Method getAction() {        return action;    }    public Class<?> getTargetType() {        return targetType;    }    @Override    public String toString() {        return httpMethod + "\t" + path;    }}//修正路径的信息哦 public static String fixPath(String path) {        if (path == null) {            return "/";        }        if (!path.startsWith("/")) {            path = "/" + path;        }        if (path.length() > 1 && path.endsWith("/")) {            path = path.substring(0, path.length() - 1);        }        return path;}

HttpMethod 枚举信息

public enum HttpMethod {    ALL, GET, POST, PUT, PATCH, DELETE, HEAD, TRACE, CONNECT, OPTIONS, BEFORE, AFTER}

Route的数据包含

  • 请求的类型
  • 请求的路径
  • 响应的Class
  • 响应的Object
  • 响应的Method
    根据以上的几点,我们根本上就可以根据请求的path路径找到相应的执行的的类的信息哦!你觉得了?是不是这个道理。

如何处理自己定义的Route

比如我们在使用spring mvc的时候,肯定在Controller层处理了好多的route对吧,那么我们怎么去获取这写处理的逻辑呢,这里进行简单的说明一下子。

下面的这个是Blade的核心类,里面包含的很多,什么Ioc,全局配置信息,自然也是拥有Routers和RouterBuilder( this.routeBuilder = new RouteBuilder(this.routers)),这里的保存的都是核心的东西,Blade是一个单例,这两个类到底是有何用?慢慢的揭晓这个答案,体会别人是怎么书写,怎么去构造这么大的工程的。

/** * Blade Core Class  */public final class Blade {    /**     * Framework Global Configuration     */    private BConfig bConfig;    /**     * Default ioc container     */    private Ioc ioc = new SimpleIoc();    /**     * Default routes 这个就是route的一个集合     */    private Routers routers = new Routers();    /**     * Route builder  这里估计就是为了构建工程中书写的route放置在routers中去     */    private RouteBuilder routeBuilder;    /**     * filters     */    private Map<Class<? extends Filter>, String[]> filters = CollectionKit.newHashMap(8);    /**     * servlets     */    private Map<Class<? extends HttpServlet>, String[]> servlets = CollectionKit.newHashMap(8);    /**     * embed web server e.g:jetty/tomcat     */    private EmbedServer embedServer;    private Blade() {        this.bConfig = new BConfig();        this.plugins = CollectionKit.newHashSet();        this.routeBuilder = new RouteBuilder(this.routers);    }    private static final class BladeHolder {        private static final Blade $ = new Blade();    }    /**     * @return Single case method returns Blade object     */    public static Blade $() {        return BladeHolder.$;    }    /**     * @return return route manager     */    public Routers routers() {        return routers;    }    /**     * Setting Ioc packages, e.g:com.bladejava.service     *     * @param packages All need to do into the package, can be introduced into a     *                 number of     * @return return blade     */    public Blade scan(String... packages) {        bConfig.addScanPackage(packages);        return this;    }    /**     * Add a route     *     * @param path   route path     * @param clazz  Target object for routing     * @param method The method name of the route (at the same time, the HttpMethod     *               is specified: post:saveUser, if not specified, HttpMethod.ALL)     * @return return blade     */    public Blade route(String path, Class<?> clazz, String method) {        routers.route(path, clazz, method);        return this;    }    /**     * regsiter filter     *     * @param clazz     * @param pathSpec     * @return     */    public Blade registerFilter(Class<? extends Filter> clazz, String... pathSpec) {        filters.put(clazz, pathSpec);        return this;    }    /**     * regsiter servlet     *     * @param clazz     * @param pathSpec     * @return     */    public Blade registerServlet(Class<? extends HttpServlet> clazz, String... pathSpec) {        servlets.put(clazz, pathSpec);        return this;    }    /**     * Register a functional route     *     * @param path       route url     * @param clazz      route processing class     * @param method     route processing method name     * @param httpMethod HttpMethod Type, GET/POST/...     * @return Blade return blade     */    public Blade route(String path, Class<?> clazz, String method, HttpMethod httpMethod) {        routers.route(path, clazz, method, httpMethod);        return this;    }    /**     * Register a GET request route     *     * @param path    route path, request url     * @param handler execute route Handle     * @return return blade     */    public Blade get(String path, RouteHandler handler) {        routers.route(path, handler, HttpMethod.GET);        return this;    }    /**     * Register a POST request route     *     * @param path    route path, request url     * @param handler execute route Handle     * @return return blade     */    public Blade post(String path, RouteHandler handler) {        routers.route(path, handler, HttpMethod.POST);        return this;    }    /**     * Register a DELETE request route     *     * @param path    route path, request url     * @param handler execute route Handle     * @return return blade     */    public Blade delete(String path, RouteHandler handler) {        routers.route(path, handler, HttpMethod.DELETE);        return this;    }    /**     * Register a PUT request route     *     * @param path    route path, request url     * @param handler execute route Handle     * @return return blade     */    public Blade put(String path, RouteHandler handler) {        routers.route(path, handler, HttpMethod.PUT);        return this;    }    /**     * Register for any request routing     *     * @param path    route path, request url     * @param handler execute route Handle     * @return return blade     */    public Blade all(String path, RouteHandler handler) {        routers.route(path, handler, HttpMethod.ALL);        return this;    }    /**     * Register for any request routing     *     * @param path    route path, request url     * @param handler execute route Handle     * @return return blade     */    public Blade any(String path, RouteHandler handler) {        routers.route(path, handler, HttpMethod.ALL);        return this;    }    /**     * Register a pre routing request interceptor     *     * @param path    route path, request url     * @param handler execute route Handle     * @return return blade     */    public Blade before(String path, RouteHandler handler) {        routers.route(path, handler, HttpMethod.BEFORE);        return this;    }    /**     * Register a after routing request interceptor     *     * @param path    route path, request url     * @param handler execute route Handle     * @return return blade     */    public Blade after(String path, RouteHandler handler) {        routers.route(path, handler, HttpMethod.AFTER);        return this;    }    /**     * Setting the frame static file folder     *     * @param statics List of directories to filter, e.g: "/public,/static,/images"     * @return return blade     */    public Blade addStatics(final String... statics) {        bConfig.addStatic(statics);        return this;    }    /**     * add interceptor     *     * @param interceptor interceptor class     * @return return blade obj     */    public Blade addInterceptor(Class<? extends Interceptor> interceptor) {        routeBuilder.addInterceptor(interceptor);        return this;    }    /**     * @return Return blade config object     */    public BConfig bConfig() {        return bConfig;    }    /**     * @return Return blade config object     */    public Config config() {        return bConfig.config();    }    /**     * @return Return blade encoding, default is UTF-8     */    public String encoding() {        return bConfig.getEncoding();    }    /**     * @return Return blade web root path     */    public String webRoot() {        return bConfig.webRoot();    }}

还记得之前controller注解?初始化Ioc的时候 ,Controller也是一样的不同的是需要处理route

classInfo 中为class< ?>和 className
下面的数据都是我们Blade这个核心类中的哦

 this.blade = Blade.$();//单例获取哦 Ioc ioc = blade.ioc(); //RouteBuilder中的routers也是blade中的哦。 RouteBuilder routeBuilder = blade.routeBuilder();

下面的我们仅仅关注route和拦截器也是属于route的一部分哦。

 classInfos.forEach(c -> {    Class< ?> clazz = c.getClazz();    if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) {        Service service = clazz.getAnnotation(Service.class);        Controller controller = clazz.getAnnotation(Controller.class);        RestController restController = clazz.getAnnotation(RestController.class);        Component component = clazz.getAnnotation(Component.class);        if (null != service || null != component) {            ioc.addBean(clazz);        } else if (null != controller || null != restController) {            ioc.addBean(clazz);            routeBuilder.addRouter(clazz);//处理注解中的route        } else if (clazz.getSuperclass().getName().equals("com.blade.aop.AbstractMethodInterceptor")) {            aopInterceptors.add(ReflectKit.newInstance(clazz));        } else {            Class< ?>[] interfaces = clazz.getInterfaces();            for (Class< ?> in : interfaces) {                if (in.equals(Interceptor.class)) {                    ioc.addBean(clazz);                    routeBuilder.addInterceptor(clazz);                } else if (in.equals(WebContextListener.class)) {                    ctxClasses.add(c);                } else if (in.equals(BeanProcessor.class)) {                    processoers.add(c);                }            }        }    }});

routerbuilder中处理Class类中的方法的注解哦,这个也是这个类的意思

基于设计模式的核心原则,单一原则(一个类只负责一件事)
addRouter,将当前类的所有的方法进行扫描,然后看看是否有注解,然后,将这个注解增加到routers中去处理涩,就是这样的逻辑。

     //Parse all routing in a controller    public void addRouter(final Class< ?> router) {        Method[] methods = router.getMethods();//得到当前Class的所有的方法        if (null == methods || methods.length == 0) {            return;        }        //route的空间和后缀        String nameSpace = null, suffix = null;        if (null != router.getAnnotation(Controller.class)) {            nameSpace = router.getAnnotation(Controller.class).value();            suffix = router.getAnnotation(Controller.class).suffix();        }        if (null != router.getAnnotation(RestController.class)) {            nameSpace = router.getAnnotation(RestController.class).value();            suffix = router.getAnnotation(RestController.class).suffix();        }        if (null == nameSpace) {            LOGGER.warn("Route [{}] not controller annotation", router.getName());            return;        }        for (Method method : methods) {            //是否含有route的注解啊            Route mapping = method.getAnnotation(Route.class);            //route method            if (null != mapping) {                // build multiple route,一个方法对应多个路由哦                HttpMethod methodType = mapping.method();                String[] paths = mapping.value();                if (paths.length > 0) {                    for (String path : paths) {                        String pathV = getRoutePath(path, nameSpace, suffix);                        this.buildRoute(router, method, pathV, methodType);                    }                }            }        }    }

修正不同的书写路径的写法

private String getRoutePath(String value, String nameSpace, String suffix) {    String path = value.startsWith("/") ? value : "/" + value;    nameSpace = nameSpace.startsWith("/") ? nameSpace : "/" + nameSpace;    path = nameSpace + path;    path = path.replaceAll("[/]+", "/");    path = path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length() - 1) : path;    path = path + suffix;    return path;}

Route的注解

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Route {    /**     * @return Request url     */    String[] value() default {"/"};    /**     * @return Request HttpMethod     */    HttpMethod method() default HttpMethod.ALL;}

将所有的route需要耳朵class,Method,path等传递过去,,routers就是处理这个的哦,里面的Map<路径对应,一个route>,将当前的route信息扔过去就好了。

     /**     * Build a route     *     * @param clazz        route target execution class     * @param execMethod    route execution method     * @param path            route path     * @param method        route httpmethod     */    private void buildRoute(Class< ?> clazz, Method execMethod, String path, HttpMethod method) {        routers.buildRoute(path, clazz, execMethod, method);    }

看看routerbuilder整个类的完整的信息,这里还有个处理就是处理过滤器哦,拦截器哈哈!道理是一个样子的!

public class RouteBuilder {    private Routers routers;    public RouteBuilder(Routers routers) {        this.routers = routers;    }    /**     * Parse Interceptor     *     * @param interceptor    resolve the interceptor class     */    public void addInterceptor(final Class<?> interceptor) {        boolean hasInterface = ReflectKit.hasInterface(interceptor, Interceptor.class);        if (null == interceptor || !hasInterface) {            return;        }        Intercept intercept = interceptor.getAnnotation(Intercept.class);        String partten = "/.*";        if (null != intercept) {            partten = intercept.value();        }        try {            Method before = interceptor.getMethod("before", Request.class, Response.class);            Method after = interceptor.getMethod("after", Request.class, Response.class);            buildInterceptor(partten, interceptor, before, HttpMethod.BEFORE);            buildInterceptor(partten, interceptor, after, HttpMethod.AFTER);        } catch (Exception e) {            LOGGER.error("", e);        }    }    /**     * Parse all routing in a controller     *     * @param router    resolve the routing class     */    public void addRouter(final Class<?> router) {        Method[] methods = router.getMethods();        if (null == methods || methods.length == 0) {            return;        }        String nameSpace = null, suffix = null;        if (null != router.getAnnotation(Controller.class)) {            nameSpace = router.getAnnotation(Controller.class).value();            suffix = router.getAnnotation(Controller.class).suffix();        }        if (null != router.getAnnotation(RestController.class)) {            nameSpace = router.getAnnotation(RestController.class).value();            suffix = router.getAnnotation(RestController.class).suffix();        }        if (null == nameSpace) {            LOGGER.warn("Route [{}] not controller annotation", router.getName());            return;        }        for (Method method : methods) {            Route mapping = method.getAnnotation(Route.class);            //route method            if (null != mapping) {                // build multiple route                HttpMethod methodType = mapping.method();                String[] paths = mapping.value();                if (paths.length > 0) {                    for (String path : paths) {                        String pathV = getRoutePath(path, nameSpace, suffix);                        this.buildRoute(router, method, pathV, methodType);                    }                }            }        }    }    private String getRoutePath(String value, String nameSpace, String suffix) {        String path = value.startsWith("/") ? value : "/" + value;        nameSpace = nameSpace.startsWith("/") ? nameSpace : "/" + nameSpace;        path = nameSpace + path;        path = path.replaceAll("[/]+", "/");        path = path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length() - 1) : path;        path = path + suffix;        return path;    }    /**     * Build a route     *     * @param clazz        route target execution class     * @param execMethod    route execution method     * @param path            route path     * @param method        route httpmethod     */    private void buildRoute(Class<?> clazz, Method execMethod, String path, HttpMethod method) {        routers.buildRoute(path, clazz, execMethod, method);    }    /**     * Build a route     *     * @param path            route path     * @param clazz        route target execution class     * @param execMethod    route execution method     * @param method        route httpmethod     */    private void buildInterceptor(String path, Class<?> clazz, Method execMethod, HttpMethod method) {        routers.buildRoute(path, clazz, execMethod, method);    }}

Routers 这个比较好理解的直接贴代码了,其实就是Map < String,Route>

我们可以自己通过函数添加,或者自动扫描添加。可以发现,routers非常的完善,可以自己随意的定义一个处理器哦!

public class Routers {    private Map<String, Route> routes = null;    private Map<String, Route> interceptors = null;    private static final String METHOD_NAME = "handle";    public Routers() {        this.routes = CollectionKit.newConcurrentHashMap();        this.interceptors = CollectionKit.newConcurrentHashMap();    }    public Map<String, Route> getRoutes() {        return routes;    }    public Map<String, Route> getInterceptors() {        return interceptors;    }   //路径的信息=path#方法名称     public void addRoute(Route route) {        String path = route.getPath();        HttpMethod httpMethod = route.getHttpMethod();        String key = path + "#" + httpMethod.toString();        // existent        if (null != this.routes.get(key)) {        }        if (httpMethod == HttpMethod.BEFORE || httpMethod == HttpMethod.AFTER) {            if (null != this.interceptors.get(key)) {            }            this.interceptors.put(key, route);            LOGGER.debug("Add Interceptor => {}", route);        } else {            this.routes.put(key, route);            LOGGER.debug("Add Route => {}", route);        }    }    public void addRoutes(List<Route> routes) {        Assert.notNull(routes);        routes.forEach(this::addRoute);    }    public void addRoute(HttpMethod httpMethod, String path, RouteHandler handler, String methodName) throws NoSuchMethodException {        Class<?> handleType = handler.getClass();        Method method = handleType.getMethod(methodName, Request.class, Response.class);        addRoute(httpMethod, path, handler, RouteHandler.class, method);    }    public void addRoute(HttpMethod httpMethod, String path, Object controller, Class<?> controllerType, Method method) {        Assert.notBlank(path);        String key = path + "#" + httpMethod.toString();        // existent        if (null != this.routes.get(key)) {        }        Route route = new Route(httpMethod, path, controller, controllerType, method);        if (httpMethod == HttpMethod.BEFORE || httpMethod == HttpMethod.AFTER) {            if (null != this.interceptors.get(key)) {            }            this.interceptors.put(key, route);            LOGGER.info("Add Interceptor: {}", route);        } else {            this.routes.put(key, route);            LOGGER.info("Add Route => {}", route);        }    }    public void route(String path, RouteHandler handler, HttpMethod httpMethod) {        try {            addRoute(httpMethod, path, handler, METHOD_NAME);        } catch (NoSuchMethodException e) {            throw new BladeException(e);        }    }    public void route(String[] paths, RouteHandler handler, HttpMethod httpMethod) {        for (String path : paths) {            route(path, handler, httpMethod);        }    }    private Map<String, Method[]> classMethosPool = CollectionKit.newConcurrentHashMap(16);    private Map<Class<?>, Object> controllerPool = CollectionKit.newConcurrentHashMap(16);    public void route(String path, Class<?> clazz, String methodName) {        Assert.notNull(methodName, "Method name not is null");        HttpMethod httpMethod = HttpMethod.ALL;        if (methodName.contains(":")) {            String[] methodArr = methodName.split(":");            httpMethod = HttpMethod.valueOf(methodArr[0].toUpperCase());            methodName = methodArr[1];        }        this.route(path, clazz, methodName, httpMethod);    }    public void route(String path, Class<?> clazz, String methodName, HttpMethod httpMethod) {        try {            Assert.notNull(path, "Route path not is null!");            Assert.notNull(clazz, "Class Type not is null!");            Assert.notNull(methodName, "Method name not is null");            Assert.notNull(httpMethod, "Request Method not is null");            Method[] methods = classMethosPool.get(clazz.getName());            if (null == methods) {                methods = clazz.getMethods();                classMethosPool.put(clazz.getName(), methods);            }            if (null != methods) {                for (Method method : methods) {                    if (method.getName().equals(methodName)) {                        Object controller = controllerPool.get(clazz);                        if (null == controller) {                            controller = ReflectKit.newInstance(clazz);                            controllerPool.put(clazz, controller);                        }                        addRoute(httpMethod, path, controller, clazz, method);                    }                }            }        } catch (Exception e) {            LOGGER.error("", e);        }    }    public void buildRoute(String path, Class<?> clazz, Method method, HttpMethod httpMethod) {        addRoute(httpMethod, path, null, clazz, method);    }}
public interface RouteHandler {    void handle(Request request, Response response);}
0 0