国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

tomcat源碼學習(2)  關于apache digest

2019-11-14 23:30:46
字體:
來源:轉載
供稿:網友
tomcat源碼學習(2)  關于apache digest

  好久不寫博文,罪過罪過。因為最近公司比較忙加上瑣事有點多,所以隔了好久才來更新博文。

  apache digest本來是struts2框架中來加載xml文件并實例化對象的一個jar包,后來使用的越來越多。我們都知道tomcat的conf文件夾下有一個server.xml配置文件,我們經常會其中的來進行配置以來運行一個java web項目,也經常修改中的port屬性以來實現修改tomcat監聽的端口。其實每個標簽基本上都對應著一個對象,那tomcat是如何將這些對象實例化到java 虛擬機的運行內存中的呢,這就是apache digest類做的事情。  上篇講到catalina的load的方法,在load方法中調用了兩個函數 
1 initDirs();2 // Before digester - it may be needed3 initNaming();
  上述兩個函數之后調用createStartDigester()。  
PRotected Digester createStartDigester() {        long t1=System.currentTimeMillis();        // Initialize the digester        Digester digester = new Digester();        digester.setValidating(false);        digester.setRulesValidation(true);        HashMap, List> fakeAttributes = new HashMap<>();        ArrayList attrs = new ArrayList<>();        attrs.add("className");        fakeAttributes.put(Object.class, attrs);        digester.setFakeAttributes(fakeAttributes);        digester.setUseContextClassLoader(true);         // Configure the actions we will be using        digester.addObjectCreate("Server",                                 "org.apache.catalina.core.StandardServer",                                 "className");        digester.addSetProperties("Server");        digester.addSetNext("Server",                            "setServer",                            "org.apache.catalina.Server");         digester.addObjectCreate("Server/GlobalNamingResources",                                 "org.apache.catalina.deploy.NamingResourcesImpl");        digester.addSetProperties("Server/GlobalNamingResources");        digester.addSetNext("Server/GlobalNamingResources",                            "setGlobalNamingResources",                            "org.apache.catalina.deploy.NamingResourcesImpl");         digester.addObjectCreate("Server/Listener",                                 null, // MUST be specified in the element                                 "className");        digester.addSetProperties("Server/Listener");        digester.addSetNext("Server/Listener",                            "addLifecycleListener",                            "org.apache.catalina.LifecycleListener");         digester.addObjectCreate("Server/Service",                                 "org.apache.catalina.core.StandardService",                                 "className");        digester.addSetProperties("Server/Service");        digester.addSetNext("Server/Service",                            "addService",                            "org.apache.catalina.Service");         digester.addObjectCreate("Server/Service/Listener",                                 null, // MUST be specified in the element                                 "className");        digester.addSetProperties("Server/Service/Listener");        digester.addSetNext("Server/Service/Listener",                            "addLifecycleListener",                            "org.apache.catalina.LifecycleListener");         //Executor        digester.addObjectCreate("Server/Service/Executor",                         "org.apache.catalina.core.StandardThreadExecutor",                         "className");        digester.addSetProperties("Server/Service/Executor");         digester.addSetNext("Server/Service/Executor",                            "addExecutor",                            "org.apache.catalina.Executor");          digester.addRule("Server/Service/Connector",                         new ConnectorCreateRule());        digester.addRule("Server/Service/Connector",                         new SetAllPropertiesRule(new String[]{"executor"}));        digester.addSetNext("Server/Service/Connector",                            "addConnector",                            "org.apache.catalina.connector.Connector");          digester.addObjectCreate("Server/Service/Connector/Listener",                                 null, // MUST be specified in the element                                 "className");        digester.addSetProperties("Server/Service/Connector/Listener");        digester.addSetNext("Server/Service/Connector/Listener",                            "addLifecycleListener",                            "org.apache.catalina.LifecycleListener");         // Add RuleSets for nested elements        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));        digester.addRuleSet(new EngineRuleSet("Server/Service/"));        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));        addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));         // When the 'engine' is found, set the parentClassLoader.        digester.addRule("Server/Service/Engine",                         new SetParentClassLoaderRule(parentClassLoader));        addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");         long t2=System.currentTimeMillis();        if (log.isDebugEnabled()) {            log.debug("Digester for server.xml created " + ( t2-t1 ));        }        return (digester);}
我們可以看到創建了一個digester對象之后,暫時不看對digester對象的各種屬性的設置set方法,我們可以看到一大堆的
addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer", "org.apache.catalina.Server");

這里就是digest對象中的所謂的各種規則了,這里看到的server就是我們在tomcat源碼學習后期看到的server對象啦,這個以后再說。

load()方法中,在創建了digester對象后,接下來調用了digester.parse(inputSource);方法即開始解析xml文件并根據上述規則開始實例化各種對象了。這里的xml文件即為conf文件下的server.xml文件拉。回過頭來再看digester對象。以下為digester類的成員變量。
protected StringBuilder bodyText = new StringBuilder();   protected ArrayStack bodyTexts = new ArrayStack<>(); protected ArrayStack> matches = new ArrayStack<>(10);   protected ClassLoader classLoader = null;   protected boolean configured = false;   protected EntityResolver entityResolver;   protected HashMap entityValidator = new HashMap<>();   protected ErrorHandler errorHandler = null;   protected SAXParserFactory factory = null;protected Locator locator = null;   protected String match = ""; protected boolean namespaceAware = false; protected HashMap> namespaces = new HashMap<>(); protected ArrayStackparams = new ArrayStack<>(); protected SAXParser parser = null; protected String publicId = null; protected XMLReader reader = null; protected Object root = null;   protected Rules rules = null;   protected ArrayStackstack = new ArrayStack<>(); protected boolean useContextClassLoader = false; protected boolean validating = false; protected boolean rulesValidation = false; protected Map, List> fakeAttributes = null;

在討論digester類是如何實現在解析xml時來實例化相應的類前,我們先看一篇博文,關于java如何解析xml的文件的 http://www.survivalescaperooms.com/topic/763895

原生java包中已經提供了sax來解析源碼的api,在解析的時候觸發不同的事件,對事件函數進行處理,我們只要繼承org.xml.sax.helpers.DefaultHandler類來實現我們的業務需求即可。最主要的是重寫startDocument(),startElement(String uri, String localName, String qName, Attributes attributes),endElement(String uri, String localName, String qName) ,characters(char[] ch, int start, int length) 函數。我們來看Digetster類的成員變量,果然含有SAXParser類和XMLReader的成員對象,這里tomcat調用的是XMLReader的parse方法。我們從
public void addObjectCreate(String pattern, String className,String attributeName) {    addRule(pattern,new ObjectCreateRule(className, attributeName));}
ObjectCreateRule 顧名思義,這是一個創建對象的規則了,繼承Rule類,Rule是一個抽象類,成員變量為protected類型,可以被子類獲取到,分別為 protected Digester digester = null; protected String namespaceURI = null;。注釋寫的很明白。還可以看到除了set,get方法之外的begin() body() end() finish()方法。這些方法將會被子類重寫以實現業務需求。后面我們將看到這些方法將會被上面談到的startElement()等方法使用到。接著看Digester類的方法
public void addRule(String pattern, Rule rule) {    rule.setDigester(this);    getRules().add(pattern, rule);}

將rule綁定到digester上,getRules()返回的是Digester類的成員變量rules,為Rules類型的成員變量,Rules是一個接口,實現有RulesBase類,成員變量如下

protected HashMap> cache = new HashMap<>();protected Digester digester = null;protected String namespaceURI = null;protected ArrayList rules = new ArrayList<>();

rules的add方法

 @Override    public void add(String pattern, Rule rule) {        // to help users who accidently add '/' to the end of their patterns        int patternLength = pattern.length();        if (patternLength>1 && pattern.endsWith("/")) {            pattern = pattern.substring(0, patternLength-1);        }         List list = cache.get(pattern);        if (list == null) {            list = new ArrayList<>();            cache.put(pattern, list);        }        list.add(rule);        rules.add(rule);        if (this.digester != null) {            rule.setDigester(this.digester);        }        if (this.namespaceURI != null) {            rule.setNamespaceURI(this.namespaceURI);        }}

即將需要匹配的pattern和rule放置到cache的hashmap中,并綁定digester和namespaceURI

后面還有兩種
digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");

分別是兩種不同的規則,就不再一一贅述了。

后面繼續還有addRuleSet,我們會發現該函數設置了一下namespace,還有增加了一堆以上的規則,比如說NamingRuleSet就增加了一堆EJB相關的規則以對EJB進行支持等等,EngineRuleSet,HostRuleSet,ContextRuleSet 應該分別對應tomcat的幾大組件engine,host,context,當然還有wrapper,也就是servlet相關的沒有出現。其中有一個addClusterRuleSet 函數是調用了反射,通過Class.forName來動態加載一個RuleSet,不知道為什么,這里先記下。上面說到是XML的parse方法。在catalina類的load方法中調用了digester的parse方法
public Object parse(InputSource input) throws IOException,SAXException {        configure();        getXMLReader().parse(input);        return (root);}protected void configure() {        // Do not configure more than once        if (configured) {            return;        }        log = LogFactory.getLog("org.apache.tomcat.util.digester.Digester");        saxLog = LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax");        // Set the configuration flag to avoid repeating        configured = true;}public XMLReader getXMLReader() throws SAXException {        if (reader == null){            reader = getParser().getXMLReader();        }        reader.setDTDHandler(this);        reader.setContentHandler(this);        if (entityResolver == null){            reader.setEntityResolver(this);        } else {            reader.setEntityResolver(entityResolver);        }        reader.setProperty(                "http://xml.org/sax/properties/lexical-handler", this);        reader.setErrorHandler(this);        return reader;}public SAXParser getParser() {        // Return the parser we already created (if any)        if (parser != null) {            return (parser);        }        // Create a new parser        try {            parser = getFactory().newSAXParser();        } catch (Exception e) {            log.error("Digester.getParser: ", e);            return (null);        }        return (parser);}

可以看到getXMLReader 方法中,設置XMLReader的解析處理handler均為digester類。主要看

reader.setContentHandler(this);

即在解析xml文件中將調用digester類中的startElement,endElement,endElement方法等。  

我們先來看startElement方法

 @Override    public void startElement(String namespaceURI, String localName,                             String qName, Attributes list)            throws SAXException {        boolean debug = log.isDebugEnabled();        if (saxLog.isDebugEnabled()) {            saxLog.debug("startElement(" + namespaceURI + "," + localName + "," +                    qName + ")");        }        // Parse system properties        list = updateAttributes(list);        // Save the body text accumulated for our surrounding element        bodyTexts.push(bodyText);        if (debug) {            log.debug("  Pushing body text '" + bodyText.toString() + "'");        }        bodyText = new StringBuilder();        // the actual element name is either in localName or qName, depending        // on whether the parser is namespace aware        String name = localName;        if ((name == null) || (name.length() < 1)) {            name = qName;        }        // Compute the current matching rule        StringBuilder sb = new StringBuilder(match);        if (match.length() > 0) {            sb.append('/');        }        sb.append(name);        match = sb.toString();        if (debug) {            log.debug("  New match='" + match + "'");        }        // Fire "begin" events for all relevant rules        List<Rule> rules = getRules().match(namespaceURI, match);        matches.push(rules);        if ((rules != null) && (rules.size() > 0)) {            for (int i = 0; i < rules.size(); i++) {                try {                    Rule rule = rules.get(i);                    if (debug) {                        log.debug("  Fire begin() for " + rule);                    }                    rule.begin(namespaceURI, name, list);                } catch (Exception e) {                    log.error("Begin event threw exception", e);                    throw createSAXException(e);                } catch (Error e) {                    log.error("Begin event threw error", e);                    throw e;                }            }        } else {            if (debug) {                log.debug("  No rules found matching '" + match + "'.");            }        }    }

我們主要看這個函數

List<Rule> rules = getRules().match(namespaceURI, match);
根據namespaceURI 和 match來匹配rule,match即xml中的標簽,我們打個斷點可以發現,第一個匹配server的其實就是上述按順序的
digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");

然后分別調用以上rule的begin方法

ObjectCreateRule的begin方法即利用反射創建了相關對象,并將該對象push到digest的成員變量protected ArrayStack<Object> stack = new ArrayStack<>();中

Class<?> clazz = digester.getClassLoader().loadClass(realClassName);Object instance = clazz.newInstance();digester.push(instance);

SetPropertiesRule的begin方法即會對處于digest的stack的棧頂元素的屬性進行設置,隱藏的很隱蔽

if (!digester.isFakeAttribute(top, name)&& !IntrospectionUtils.setProperty(top, name, value)&& digester.getRulesValidation()) {    digester.log.warn("[SetPropertiesRule]{" + digester.match +                        "} Setting property '" + name + "' to '" +                        value + "' did not find a matching property.");}

在!IntrospectionUtils.setProperty(top, name, value)中進行了設置。

SetNextRule中未對begin方法進行重載,不進行描述

接下來是characters(char buffer[], int start, int length) 方法

@Override    public void characters(char buffer[], int start, int length)            throws SAXException {        if (saxLog.isDebugEnabled()) {            saxLog.debug("characters(" + new String(buffer, start, length) + ")");        }        bodyText.append(buffer, start, length);    }

僅是對bodyText進行append

接下來就是end方法了

無非即對其中的stack進行一系列的pop,并調用了rule的body方法,這里很多繼承的rule并未重寫body方法,這里不做表述。

還有一點要說明的是,digest類中的成員變量:protected ArrayStack<Object> stack = new ArrayStack<>();是一個通過ArrayList實現的 stack

其中startElement和endElement未做描述,感興趣的可以自己查閱源代碼看,至此結束。

我們可以認為digest使用了decorator設計模式,為了在該類上實現更多的功能,利用一個list,來不斷調用不同rule中的方法。

有不足或錯誤,敬請指正,thanks。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 伊金霍洛旗| 堆龙德庆县| 榆社县| 开封市| 营口市| 东源县| 淄博市| 敖汉旗| 田阳县| 丽水市| 木里| 克东县| 张家口市| 江都市| 监利县| 上思县| 云梦县| 佛学| 武威市| 福安市| 宁夏| 台山市| 渝北区| 韶山市| 元朗区| 芜湖市| 樟树市| 兴安县| 县级市| 金坛市| 施甸县| 兴安盟| 昌图县| 太谷县| 安泽县| 曲水县| 宜丰县| 从江县| 天长市| 寻乌县| 嘉义县|