1. 程式人生 > >mybatis-generator原始碼解讀系列(三):配置讀取

mybatis-generator原始碼解讀系列(三):配置讀取

概述:

        配置讀取是程式碼生成的基礎工作,主要就是把xml中的元資料讀取到記憶體中,供後面的程式碼生成邏輯使用

相關類

1、ConfigurationParser

功能

        主要用來將xml配置檔案讀取到記憶體,獲取根節點,根據根節點的屬性值,選擇對應的子節點的配置解析器

程式碼解讀:

1)讀取xml

            // dcoument 組裝器
            DocumentBuilder builder = factory.newDocumentBuilder();
            builder.setEntityResolver(new ParserEntityResolver());

            // 例項化一個錯誤處理類,處理的錯誤和警告資訊會以list形式儲存
            ParserErrorHandler handler = new ParserErrorHandler(warnings,
                    parseErrors);
            builder.setErrorHandler(handler);
            // 使用w3c 文件解析
            Document document = null;
            try {
            	// 將記憶體檔案轉換為w3c文件物件
                document = builder.parse(inputSource);
            } catch (SAXParseException e) {
            	// 拋除自定義xml轉換錯誤異常
                throw new XMLParserException(parseErrors);
            } catch (SAXException e) {
            	// 其他異常處理
                if (e.getException() == null) {
                    parseErrors.add(e.getMessage());
                } else {
                    parseErrors.add(e.getException().getMessage());
                }
            }
             // 有錯的情況下,丟擲異常終止執行
            if (parseErrors.size() > 0) {
                throw new XMLParserException(parseErrors);
            }

2、解析根節點,根據元資料值獲取子節點解析器    

            // 返回的配置檔案物件
            Configuration config;
            // 獲取根節點 
            Element rootNode = document.getDocumentElement();
            // 獲取文件型別 
            DocumentType docType = document.getDoctype();
            if (rootNode.getNodeType() == Node.ELEMENT_NODE
                    && docType.getPublicId().equals(
                            XmlConstants.IBATOR_CONFIG_PUBLIC_ID)) {
                config = parseIbatorConfiguration(rootNode);
            } else if (rootNode.getNodeType() == Node.ELEMENT_NODE
                    && docType.getPublicId().equals(
                            XmlConstants.MYBATIS_GENERATOR_CONFIG_PUBLIC_ID)) {
            	// -//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN
            	// 該DTD執行此分支,也就是mybatis處理分支
                config = parseMyBatisGeneratorConfiguration(rootNode);
            } else {
                throw new XMLParserException(getString("RuntimeError.5")); //$NON-NLS-1$
            }

            if (parseErrors.size() > 0) {
                throw new XMLParserException(parseErrors);
            }

2、MyBatisGeneratorConfigurationParser

功能:

主要實現子節點解析工作,同時把所有的元資料載入到記憶體,供後續解析使用

程式碼解讀:

1)屬性、資料庫類驅動以及上下解析    

            if ("properties".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseProperties(configuration, childNode);
            } else if ("classPathEntry".equals(childNode.getNodeName())) { //$NON-NLS-1$
            	// 轉換類路徑節點,轉換的元素賦值給配置物件
                parseClassPathEntry(configuration, childNode);
            } else if ("context".equals(childNode.getNodeName())) { //$NON-NLS-1$
            	// 轉換上下文節點,轉換的元素賦值給配置物件
                parseContext(configuration, childNode);
            }
2)解析上下文,將所有的元資料載入到記憶體上下文,生成程式碼時使用這些資料(如:生成哪些類、報名、類名等)
        // 獲取context的所有屬性以及值
        Properties attributes = parseAttributes(node);
        String defaultModelType = attributes.getProperty("defaultModelType"); //$NON-NLS-1$
        String targetRuntime = attributes.getProperty("targetRuntime"); //$NON-NLS-1$
        String introspectedColumnImpl = attributes
                .getProperty("introspectedColumnImpl"); //$NON-NLS-1$
        String id = attributes.getProperty("id"); //$NON-NLS-1$


        ModelType mt = defaultModelType == null ? null : ModelType
                .getModelType(defaultModelType);
        System.err.println("parseContext | 獲取預設的模型型別:" + mt);


        // 例項化一個上下文,並將模型型別傳入構造方法,如果為null則是適用condition
        Context context = new Context(mt);
        context.setId(id);
        if (stringHasValue(introspectedColumnImpl)) {
            context.setIntrospectedColumnImpl(introspectedColumnImpl);
        }
        if (stringHasValue(targetRuntime)) {
            context.setTargetRuntime(targetRuntime);
        }


        // 將上下文放到配置物件中
        configuration.addContext(context);


        // 獲取上下問的子節點,遍歷轉換
        NodeList nodeList = node.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node childNode = nodeList.item(i);


            if (childNode.getNodeType() != Node.ELEMENT_NODE) {
                continue;
            }


            if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseProperty(context, childNode);
            } else if ("plugin".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parsePlugin(context, childNode);
            } else if ("commentGenerator".equals(childNode.getNodeName())) { //$NON-NLS-1$
            // 註釋轉換
                parseCommentGenerator(context, childNode);
            } else if ("jdbcConnection".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseJdbcConnection(context, childNode);
            } else if ("connectionFactory".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseConnectionFactory(context, childNode);
            } else if ("javaModelGenerator".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseJavaModelGenerator(context, childNode);
            } else if ("javaTypeResolver".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseJavaTypeResolver(context, childNode);
            } else if ("sqlMapGenerator".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseSqlMapGenerator(context, childNode);
            } else if ("javaClientGenerator".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseJavaClientGenerator(context, childNode);
            } else if ("table".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseTable(context, childNode);
            }

3)解讀每個具體屬性到各自記憶體配置物件中

JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();

        context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);

        Properties attributes = parseAttributes(node);
        String type = attributes.getProperty("type"); //$NON-NLS-1$
        String targetPackage = attributes.getProperty("targetPackage"); //$NON-NLS-1$
        String targetProject = attributes.getProperty("targetProject"); //$NON-NLS-1$
        String implementationPackage = attributes
                .getProperty("implementationPackage"); //$NON-NLS-1$

        javaClientGeneratorConfiguration.setConfigurationType(type);
        javaClientGeneratorConfiguration.setTargetPackage(targetPackage);
        javaClientGeneratorConfiguration.setTargetProject(targetProject);
        javaClientGeneratorConfiguration
                .setImplementationPackage(implementationPackage);

        NodeList nodeList = node.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node childNode = nodeList.item(i);

            if (childNode.getNodeType() != Node.ELEMENT_NODE) {
                continue;
            }

            if ("property".equals(childNode.getNodeName())) { //$NON-NLS-1$
                parseProperty(javaClientGeneratorConfiguration, childNode);
            }
        }
※ 上面解讀具體解讀的程式碼都雷同,首先需要各自節點的一個配置類(JavaClientGeneratorConfiguration ),然後將資料讀取到該類的例項物件中,同時將該物件注入到記憶體上下文中(Context)。