ARouter 源碼學習之Compiler

ARouter 源碼學習之Compiler

官方文檔:
Android平臺頁面路由框架ARouterjava

阿里巴巴Arouter github地址以下:
ARouter gitHub 地址android

ARouter個人學習註釋GitHub地址:
ARoutergit

Arouter 使用Demo:
Android_Modularization_Demogithub

AbstractProcessor不太熟悉的同窗,能夠參考:
Android中使用AbstractProcessor在編譯時生成代碼
基礎篇:帶你從頭至尾玩轉註解數組

該文章參考:
阿里路由框架--ARouter 源碼解析之Compiler
基礎篇:帶你從頭至尾玩轉註解app

001.jpeg

002.png

arouter-compiler 經過AbstractProcessor在編譯時生成相關類文件框架

生成的文件位於如下目錄:
003.pngide

Compiler層SDK

  • RouteProcessor 路由路徑處理器
  • InterceptorProcessor 攔截器處理器
  • AutowireProcessor 自動裝配處理器

004.png

上圖所示就是ARouter在編譯期間生成的類文件。函數

  • 紅色標註的是 RouteProcessor 生成的類文件
  • 藍色標註的是 InterceptorProcessor 生成的類文件
  • 橙色標書的是 AutowiredProcessor 生成的類文件

RouteProcessor.java

package com.alibaba.android.arouter.compiler.processor;

/**
 * A processor used for find route.
 *
 * @author Alex <a href="mailto:zhilong.liu@aliyun.com">Contact me.</a>
 * @version 1.0
 * @since 16/8/15 下午10:08
 */
// 主要的做用是註解 processor 類,並對其生成 META-INF 的配置信息。
@AutoService(Processor.class)
// ??????????????
// 這個註解用來註冊可能經過命令行傳遞給處理器的操做選項
@SupportedOptions(KEY_MODULE_NAME)
// 標識該處理器支持的源碼版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)

// 這個 Processor 要處理的 Annotation 名字
// com.alibaba.android.arouter.facade.annotation.Route
// com.alibaba.android.arouter.facade.annotation.Autowired
@SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})
public class RouteProcessor extends AbstractProcessor {

    // Filter用來建立新的源文件,class文件以及輔助文件
    private Filer mFiler;       // File util, write class file into disk.

    /**
     * 參考:
     * http://blog.csdn.net/dd864140130/article/details/53875814
     * <p>
     * Elements 中包含用於操做Element的工具方法
     * element表示一個靜態的,語言級別的構件。
     * 而任何一個結構化文檔均可以看做是由不一樣的element組成的結構體,好比XML,JSON等。
     * 對於java源文件來講,他一樣是一種結構化文檔:
     * package com.closedevice;             //PackageElement
     * public class Main{                   //TypeElement
     * private int x;                       //VariableElement
     * private Main(){                      //ExecuteableElement
     * }
     * private void print(String msg){      //其中的參數部分String msg爲TypeElement
     * }
     * }
     */
    private Elements elements;
    // Types中包含用於操做TypeMirror的工具方法
    private Types types;
    // TypeMirror表明java語言中的類型.
    // Types包括基本類型,聲明類型(類類型和接口類型),數組,類型變量和空類型。也表明通配類型參數,可執行文件的簽名和返回類型等。
    // TypeMirror類中最重要的是getKind()方法,該方法返回TypeKind類型,爲了方便你們理解
    // Element表明源代碼,TypeElement表明的是源碼中的類型元素,好比類。
    // 雖然咱們能夠從TypeElement中獲取類名,TypeElement中不包含類自己的信息,
    // 好比它的父類,要想獲取這信息須要藉助TypeMirror,能夠經過Element中的asType()獲取元素對應的TypeMirror
    private TypeMirror iProvider = null;

    // 判斷Element類型
    private TypeUtils typeUtils;


    //
    // ModuleName and routeMeta.
    // 例:
    // group='test'
    // {type=FRAGMENT,
    // rawType=com.alibaba.android.arouter.demo.BlankFragment,
    // destination=null,
    // path='/test/fragment',
    // group='test',
    // priority=-1,
    // extra=-2147483648}
    private Map<String, Set<RouteMeta>> groupMap = new HashMap<>();
    // 例:
    // group: test
    // group: ARouter$$Group$$test
    private Map<String, String> rootMap = new TreeMap<>();  // Map of root metas, used for generate class file in order.

    private String moduleName = null;   // Module name, maybe its 'app' or others


    // 日誌封裝
    // 經過Messager來報告錯誤,警告和其餘提示信息
    private Logger logger;

    /**
     * Initializes the processor with the processing environment by
     * setting the {@code processingEnv} field to the value of the
     * {@code processingEnv} argument.  An {@code
     * IllegalStateException} will be thrown if this method is called
     * more than once on the same object.
     *
     * @param processingEnv environment to access facilities the tool framework
     *                      provides to the processor
     * @throws IllegalStateException if this method is called more than once.
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        // Generate class.
        // Filter用來建立新的源文件,class文件以及輔助文件
        mFiler = processingEnv.getFiler();


        // Get class meta.
        // Elements 中包含用於操做Element的工具方法
        elements = processingEnv.getElementUtils();
        // Get type utils.
        types = processingEnv.getTypeUtils();
        // 判斷Element類型
        typeUtils = new TypeUtils(types, elements);

        // Messager用來報告錯誤,警告和其餘提示信息
        logger = new Logger(processingEnv.getMessager());   // Package the log utils.

        // Attempt to get user configuration [moduleName]
        Map<String, String> options = processingEnv.getOptions();

        logger.info("RouteProcessor options: " + options);
        if (MapUtils.isNotEmpty(options)) {
            moduleName = options.get(KEY_MODULE_NAME);
        }
        logger.info("RouteProcessor moduleName: " + moduleName);

        if (StringUtils.isNotEmpty(moduleName)) {
            moduleName = moduleName.replaceAll("[^0-9a-zA-Z_]+", "");

            logger.info("The user has configuration the module name, it was [" + moduleName + "]");
        } else {
            logger.error("These no module name, at 'build.gradle', like :\n" +
                    "apt {\n" +
                    "    arguments {\n" +
                    "        moduleName project.getName();\n" +
                    "    }\n" +
                    "}\n");
            throw new RuntimeException("ARouter::Compiler >>> No module name, for more information, look at gradle log.");
        }

        iProvider = elements.getTypeElement(Consts.IPROVIDER).asType();

        logger.info(">>> RouteProcessor init. <<<");
    }

    /**
     * {@inheritDoc}
     *
     * @param annotations
     * @param roundEnv
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        logger.info("RouteProcessor process");
        if (CollectionUtils.isNotEmpty(annotations)) {
            Set<? extends Element> routeElements = roundEnv.getElementsAnnotatedWith(Route.class);
            try {
                logger.info(">>> Found routes, start... <<<");
                this.parseRoutes(routeElements);

            } catch (Exception e) {
                logger.error(e);
            }
            return true;
        }

        return false;
    }

    /**
     * @param routeElements
     * @throws IOException
     */
    private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
        logger.info("RouteProcessor parseRoutes");
        if (CollectionUtils.isNotEmpty(routeElements)) {
            // Perpare the type an so on.

            logger.info(">>> Found routes, size is " + routeElements.size() + " <<<");

            rootMap.clear();

            // 獲取ACTIVITY, SERVICE, FRAGMENT, FRAGMENT_V4 這四種 類型鏡像
            // android.app.Activity
            TypeMirror type_Activity = elements.getTypeElement(ACTIVITY).asType();
            // android.app.Service
            TypeMirror type_Service = elements.getTypeElement(SERVICE).asType();
            // android.app.Fragment
            TypeMirror fragmentTm = elements.getTypeElement(FRAGMENT).asType();
            // android.support.v4.app.Fragment
            TypeMirror fragmentTmV4 = elements.getTypeElement(Consts.FRAGMENT_V4).asType();

            // ARouter的接口
            // Interface of ARouter
            // IRouteGroup
            TypeElement type_IRouteGroup = elements.getTypeElement(IROUTE_GROUP);
            // IProviderGroup
            TypeElement type_IProviderGroup = elements.getTypeElement(IPROVIDER_GROUP);

            // 下面就是遍歷獲取的註解信息,經過javapoet來生成類文件了
            // RouteMeta
            ClassName routeMetaCn = ClassName.get(RouteMeta.class);
            // RouteType
            ClassName routeTypeCn = ClassName.get(RouteType.class);

            /**
             *
             * public class ARouter$$Root$$app implements IRouteRoot {
             * @Override
             * public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
             * routes.put("service", ARouter$$Group$$service.class);
             * routes.put("test", ARouter$$Group$$test.class);
             * }
             * }
             *
             */

            /**
             * ParameterizedTypeName用來建立類型對象,例以下面
             *
             * Build input type, format as :
             * ```Map<String, Class<? extends IRouteGroup>>```
             */
            ParameterizedTypeName inputMapTypeOfRoot = ParameterizedTypeName.get(
                    ClassName.get(Map.class),
                    ClassName.get(String.class),
                    ParameterizedTypeName.get(
                            ClassName.get(Class.class),
                            WildcardTypeName.subtypeOf(ClassName.get(type_IRouteGroup))
                    )
            );


            /**
             *
             * public class ARouter$$Group$$test implements IRouteGroup {
             * @Override public void loadInto(Map<String, RouteMeta> atlas) {
             * atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("pac", 9); put("ch", 5); put("fl", 6); put("obj", 10); put("name", 8); put("dou", 7); put("boy", 0); put("objList", 10); put("map", 10); put("age", 3); put("url", 8); put("height", 3); }}, -1, -2147483648));
             * atlas.put("/test/activity2", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/activity2", "test", new java.util.HashMap<String, Integer>(){{put("key1", 8); }}, -1, -2147483648));
             * }
             * }
             *
             *
             */

            /**
             * RouteMeta封裝了路由相關的信息
             *
             *```Map<String, RouteMeta>```
             */
            ParameterizedTypeName inputMapTypeOfGroup = ParameterizedTypeName.get(
                    ClassName.get(Map.class),
                    ClassName.get(String.class),
                    ClassName.get(RouteMeta.class)
            );

            /*
              Build input param name.
             */
            // 一、生成的參數:Map<String, Class<? extends IRouteGroup>> routes
            ParameterSpec rootParamSpec = ParameterSpec.builder(inputMapTypeOfRoot, "routes").build();
            // 二、 Map<String, RouteMeta> atlas
            ParameterSpec groupParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "atlas").build();
            // 三、Map<String, RouteMeta> providers
            ParameterSpec providerParamSpec = ParameterSpec.builder(inputMapTypeOfGroup, "providers").build();  // Ps. its param type same as groupParamSpec!

            /**
             * Build method : 'loadInto'
             *
             * @Override
             * public void loadInto(Map<String, Class<? extends IRouteGroup>> routes)
             */
            MethodSpec.Builder loadIntoMethodOfRootBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(rootParamSpec);

            logger.info("RouteProcessor routeElements.size() " + routeElements.size());

            // 接下來的代碼就是遍歷註解元素,進行分組,進而生成java文件
            //  Follow a sequence, find out metas of group first, generate java file, then statistics them as root.
            for (Element element : routeElements) {

                logger.info("element " + element.getSimpleName());

                // TypeMirror表明java語言中的類型
                TypeMirror tm = element.asType();
                //
                Route route = element.getAnnotation(Route.class);
                //
                RouteMeta routeMete = null;

                // 判斷類型 Activity
                if (types.isSubtype(tm, type_Activity)) {                 // Activity
                    logger.info(">>> Found activity route: " + tm.toString() + " <<<");

                    // 遍歷查找全部添加 @AutoWired 註解的變量
                    // Get all fields annotation by @Autowired
                    Map<String, Integer> paramsType = new HashMap<>();
                    //
                    for (Element field : element.getEnclosedElements()) {
                        // 參數 自動裝填
                        // 1. 必須是field
                        // 2. 必須有註解AutoWired
                        // 3. 必須不是IProvider類型
                        if (field.getKind().isField()
                                && field.getAnnotation(Autowired.class) != null
                                && !types.isSubtype(field.asType(), iProvider)) {

                            logger.info("Autowired field " + field.getSimpleName());

                            // 知足上述條件後,獲取註解
                            // It must be field, then it has annotation, but it not be provider.
                            Autowired paramConfig = field.getAnnotation(Autowired.class);

                            // Autowired支持寫別名,當指定name屬性以後,就會以name爲準,不然以field的名字爲準。
                            // TypeUtils是自定義工具類,用來判斷field的數據類型的,轉換成int值。
                            paramsType.put(
                                    StringUtils.isEmpty(paramConfig.name())
                                            ? field.getSimpleName().toString()
                                            : paramConfig.name()
                                    , typeUtils.typeExchange(field));
                        }
                    }

                    logger.info("Autowired route.group " + route.group());
                    logger.info("Autowired route.name " + route.name());
                    logger.info("Autowired route.path " + route.path());
                    logger.info("Autowired route.extras " + route.extras());

                    logger.info("element " + element.getSimpleName());

                    logger.info("paramsType " + paramsType);

                    /**
                     * route: /test/activity1
                     * element: Test1Activity
                     * ACTIVITY(0, "android.app.Activity")
                     * paramsType 參數  參數對應類型int
                     */
                    routeMete = new RouteMeta(route, element, RouteType.ACTIVITY, paramsType);
                }
                // 若是是IProvider類型的註解,則直接建立一條PROVIDER類型的路由信息
                else if (types.isSubtype(tm, iProvider)) {         // IProvider
                    logger.info(">>> Found provider route: " + tm.toString() + " <<<");
                    routeMete = new RouteMeta(route, element, RouteType.PROVIDER, null);
                }
                // 若是是Service類型的註解,則直接建立一條Service類型的路由信息
                else if (types.isSubtype(tm, type_Service)) {           // Service
                    logger.info(">>> Found service route: " + tm.toString() + " <<<");
                    routeMete = new RouteMeta(route, element, RouteType.parse(SERVICE), null);
                }
                // 若是是fragmentTmV4類型的註解,則直接建立一條Fragment類型的路由信息
                else if (types.isSubtype(tm, fragmentTm) || types.isSubtype(tm, fragmentTmV4)) {
                    logger.info(">>> Found fragment route: " + tm.toString() + " <<<");
                    routeMete = new RouteMeta(route, element, RouteType.parse(FRAGMENT), null);
                } else {
                    throw new RuntimeException("ARouter::Compiler >>> Found unsupported class type, type = [" + types.toString() + "].");
                }
                // 將路由信息進行分組,分組信息保存到 groupMap中
                categories(routeMete);

            }

            /**
             * @Override
             * public void loadInto(Map<String, RouteMeta> providers)
             */
            MethodSpec.Builder loadIntoMethodOfProviderBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(providerParamSpec);

            // 遍歷 groupMap
            //
            // Start generate java source, structure is divided into upper and lower levels, used for demand initialization.
            for (Map.Entry<String, Set<RouteMeta>> entry : groupMap.entrySet()) {

                // 組名稱
                String groupName = entry.getKey();

                /**
                 * @Override
                 * public void loadInto(Map<String, RouteMeta> atlas)
                 */
                MethodSpec.Builder loadIntoMethodOfGroupBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                        .addAnnotation(Override.class)
                        .addModifiers(PUBLIC)
                        .addParameter(groupParamSpec);

                // 構建loadInto方法的方法體
                // Build group method body
                Set<RouteMeta> groupData = entry.getValue();
                // 循環
                for (RouteMeta routeMeta : groupData) {
                    // 類型
                    switch (routeMeta.getType()) {
                        // PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider")
                        case PROVIDER:// Need cache provider's super class
                            //
                            List<? extends TypeMirror> interfaces = ((TypeElement) routeMeta.getRawType()).getInterfaces();
                            // 遍歷當前類的接口
                            for (TypeMirror tm : interfaces) {
                                // 若是當前類直接實現了IProvider接口
                                if (types.isSameType(tm, iProvider)) {   // Its implements iProvider interface himself.
                                    // This interface extend the IProvider, so it can be used for mark provider
                                    /**
                                     * @Route(path = "/service/single")
                                     * public class SingleService implements IProvider
                                     *
                                     * providers.put("com.alibaba.android.arouter.demo.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/service/single", "service", null, -1, -2147483648));
                                     */
                                    loadIntoMethodOfProviderBuilder.addStatement(
                                            "providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
                                            (routeMeta.getRawType()).toString(),
                                            routeMetaCn,
                                            routeTypeCn,
                                            ClassName.get((TypeElement) routeMeta.getRawType()),
                                            routeMeta.getPath(),
                                            routeMeta.getGroup());
                                }
                                // 若是是接口繼承的IProvider
                                else if (types.isSubtype(tm, iProvider)) {
                                    /**
                                     * @Route(path = "/service/hello")
                                     * public class HelloServiceImpl implements HelloService
                                     * public interface HelloService extends IProvider
                                     * //
                                     * providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/service/hello", "service", null, -1, -2147483648));
                                     */
                                    // This interface extend the IProvider, so it can be used for mark provider
                                    loadIntoMethodOfProviderBuilder.addStatement(
                                            "providers.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, null, " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
                                            tm.toString(),    // So stupid, will duplicate only save class name.
                                            routeMetaCn,
                                            routeTypeCn,
                                            ClassName.get((TypeElement) routeMeta.getRawType()),
                                            routeMeta.getPath(),
                                            routeMeta.getGroup());
                                }
                            }
                            break;
                        default:
                            break;
                    }

                    // 形式如: put("pac", 9); put("obj", 10);
                    // Make map body for paramsType
                    StringBuilder mapBodyBuilder = new StringBuilder();
                    Map<String, Integer> paramsType = routeMeta.getParamsType();
                    if (MapUtils.isNotEmpty(paramsType)) {
                        for (Map.Entry<String, Integer> types : paramsType.entrySet()) {
                            mapBodyBuilder.append("put(\"").append(types.getKey()).append("\", ").append(types.getValue()).append("); ");
                        }
                    }
                    String mapBody = mapBodyBuilder.toString();

                    /**
                     * atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity1", "test", new java.util.HashMap<String, Integer>(){{put("pac", 9); put("ch", 5); put("fl", 6); put("obj", 10); put("name", 8); put("dou", 7); put("boy", 0); put("objList", 10); put("map", 10); put("age", 3); put("url", 8); put("height", 3); }}, -1, -2147483648));
                     */
                    loadIntoMethodOfGroupBuilder.addStatement(
                            "atlas.put($S, $T.build($T." + routeMeta.getType() + ", $T.class, $S, $S, " + (StringUtils.isEmpty(mapBody) ? null : ("new java.util.HashMap<String, Integer>(){{" + mapBodyBuilder.toString() + "}}")) + ", " + routeMeta.getPriority() + ", " + routeMeta.getExtra() + "))",
                            routeMeta.getPath(),
                            routeMetaCn,
                            routeTypeCn,
                            ClassName.get((TypeElement) routeMeta.getRawType()),
                            routeMeta.getPath().toLowerCase(),
                            routeMeta.getGroup().toLowerCase());
                }

                // Generate groups
                String groupFileName = NAME_OF_GROUP + groupName;
                //
                JavaFile.builder(
                        // package 名稱 --"com.alibaba.android.arouter.routes"
                        PACKAGE_OF_GENERATE_FILE,
                        //java類名
                        TypeSpec.classBuilder(groupFileName)
                                // doc
                                .addJavadoc(WARNING_TIPS)
                                // 添加繼承的接口
                                .addSuperinterface(ClassName.get(type_IRouteGroup))
                                // 做用域爲public
                                .addModifiers(PUBLIC)
                                // 添加函數(包括了函數裏面的代碼塊)
                                .addMethod(loadIntoMethodOfGroupBuilder.build())
                                .build()
                ).build().writeTo(mFiler);

                logger.info("---rootMap---");
                logger.info(">>> Generated group: " + groupName + "<<<");
                logger.info(">>> Generated group: " + groupFileName + "<<<");
                rootMap.put(groupName, groupFileName);
            }

            if (MapUtils.isNotEmpty(rootMap)) {
                // Generate root meta by group name, it must be generated before root, then I can find out the class of group.
                for (Map.Entry<String, String> entry : rootMap.entrySet()) {
                    loadIntoMethodOfRootBuilder.addStatement("routes.put($S, $T.class)", entry.getKey(), ClassName.get(PACKAGE_OF_GENERATE_FILE, entry.getValue()));
                }
            }

            // Wirte provider into disk
            String providerMapFileName = NAME_OF_PROVIDER + SEPARATOR + moduleName;
            JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                    TypeSpec.classBuilder(providerMapFileName)
                            .addJavadoc(WARNING_TIPS)
                            .addSuperinterface(ClassName.get(type_IProviderGroup))
                            .addModifiers(PUBLIC)
                            .addMethod(loadIntoMethodOfProviderBuilder.build())
                            .build()
            ).build().writeTo(mFiler);

            logger.info(">>> Generated provider map, name is " + providerMapFileName + " <<<");

            // Write root meta into disk.
            String rootFileName = NAME_OF_ROOT + SEPARATOR + moduleName;
            JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                    TypeSpec.classBuilder(rootFileName)
                            .addJavadoc(WARNING_TIPS)
                            .addSuperinterface(ClassName.get(elements.getTypeElement(ITROUTE_ROOT)))
                            .addModifiers(PUBLIC)
                            .addMethod(loadIntoMethodOfRootBuilder.build())
                            .build()
            ).build().writeTo(mFiler);

            logger.info(">>> Generated root, name is " + rootFileName + " <<<");
        }
    }

    /**
     * Sort metas in group.
     * <p>
     * 將路由信息進行分組,分組信息保存到 groupMap中
     * <p>
     * (每一個路由信息對象中都保存着它所屬的組別信息,在調用categories()函數以前全部的組別信息都是默認值"" )
     *
     * @param routeMete metas.
     */
    private void categories(RouteMeta routeMete) {
        logger.info("---categories---");
        // 一、驗證路由信息的正確性
        // 二、截取路徑字符串 獲取group
        if (routeVerify(routeMete)) {
            logger.info(">>> Start categories, group = " + routeMete.getGroup() + ", path = " + routeMete.getPath() + " <<<");
            // 嘗試從groupMap中經過group名稱 獲取集合數據
            Set<RouteMeta> routeMetas = groupMap.get(routeMete.getGroup());
            // 集合數據爲空
            if (CollectionUtils.isEmpty(routeMetas)) {
                // 建立組
                Set<RouteMeta> routeMetaSet = new TreeSet<>(new Comparator<RouteMeta>() {
                    @Override
                    public int compare(RouteMeta r1, RouteMeta r2) {
                        try {
                            return r1.getPath().compareTo(r2.getPath());
                        } catch (NullPointerException npe) {
                            logger.error(npe.getMessage());
                            return 0;
                        }
                    }
                });
                // 添加到新建立的集合中
                routeMetaSet.add(routeMete);
                // 集合添加到groupMap中
                groupMap.put(routeMete.getGroup(), routeMetaSet);

                logger.info("routeMete: " + routeMete);
                logger.info("routeMete.getGroup(): " + routeMete.getGroup());
            } else {
                // 添加到組中
                routeMetas.add(routeMete);
            }
        } else {
            logger.warning(">>> Route meta verify error, group is " + routeMete.getGroup() + " <<<");
        }
    }

    /**
     * 一、驗證路由信息的正確性
     * 二、截取路徑字符串 獲取group
     * <p>
     * Verify the route meta
     *
     * @param meta raw meta
     */
    private boolean routeVerify(RouteMeta meta) {
        String path = meta.getPath();

        // 合法性判斷
        if (StringUtils.isEmpty(path) || !path.startsWith("/")) {   // The path must be start with '/' and not empty!
            return false;
        }
        // 沒有分組時,group爲""
        if (StringUtils.isEmpty(meta.getGroup())) { // Use default group(the first word in path)
            try {
                // 截取路徑字符串 獲取group
                String defaultGroup = path.substring(1, path.indexOf("/", 1));
                if (StringUtils.isEmpty(defaultGroup)) {
                    return false;
                }

                meta.setGroup(defaultGroup);
                return true;
            } catch (Exception e) {
                logger.error("Failed to extract default group! " + e.getMessage());
                return false;
            }
        }

        return true;
    }
}
相關文章
相關標籤/搜索