?
轉自: http://klcwt.iteye.com/blog/749652
?
我們在編寫自定義標簽的時候設置屬性如下
- public ? class ?InputTag? extends ?TagSupport?{??
- ??
- ???? private ? static ? final ? long ?serialVersionUID?=?1L;??
- ??
- ???? private ?String?onclick;??
- ??
- ???? private ?String?style;??
- ??
- ???? private ?String?styleClass;??
- ??
- ???? private ?String?value;??
- ??
- ???? private ?String?id;??
?
在頁面上如果同時使用兩個標簽:
- < h3:input ? type = "button" ? onclick = "myFun()" ? name = "name" ? id = "id" ??
- ???????? style = "style" ? styleClass = "styleClass" ? value = "中國人" ? url = "url" ??
- ???????? pid = "pid" ? isValidated = "true" > ??
- ????中國人??
- ???? </ h3:input > ??
- ??????
- ???? < h3:input ? type = "button" ? onclick = "myFun()" ? name = "name" ? id = "id" ??
- ???????? style = "style" ? styleClass = "styleClass" ? value = "美國人" ? url = "url" ??
- ???????? pid = "pid" ? isValidated = "true" > ??
- ???? </ h3:input > ??
?
從后臺發現打印的InpuTag都是 同一個對象!
?
發現這個后,我十分擔心線程安全問題!比如這些getType();setType(); !
?
于是就看了下jsp生成的Servlet源代碼
- out.write( "\t<body>\r\n" );??
- ??out.write( "\t\t" );??
- ??? //調用InputTag ??
- ?? if ?(_jspx_meth_h3_005finput_005f0(_jspx_page_context))??
- ???? return ;??
- ??out.write( "\r\n" );??
- ??out.write( "\t\t\r\n" );??
- ??out.write( "\t\t" );??
- ?? //調用InputTag ??
- ?? if ?(_jspx_meth_h3_005finput_005f1(_jspx_page_context))??
- ???? return ;??
- ??out.write( "\r\n" );??
- ??out.write( "\t</body>\r\n" );??
?
再接著看_jspx_meth_h3_005finput_005f0方法
- ?? private ? boolean ?_jspx_meth_h3_005finput_005f0(PageContext?_jspx_page_context)??
- ?????????? throws ?Throwable?{??
- ????PageContext?pageContext?=?_jspx_page_context;??
- ????JspWriter?out?=?_jspx_page_context.getOut();??
- ???? //??h3:input ??
- ???<span?style= "color:?#ff0000;" >?tag.InputTag?<span?style= "color:?#0000ff;" >_jspx_th_h3_005finput_005f0</span>?=?(tag.InputTag)?_005fjspx_005ftagPool_005fh3_005finput_0026_005fvalue_005furl_005ftype_005fstyleClass_005fstyle_005fpid_005fonclick_005fname_005fisValidated_005fid.get(tag.InputTag. class );</span>??
- ????_jspx_th_h3_005finput_005f0.setPageContext(_jspx_page_context);??
- ????_jspx_th_h3_005finput_005f0.setParent( null );??
- ???? //?/button2.jsp(12,2)?name?=?type?type?=?null?reqTime?=?true?required?=?false?fragment?=?false?deferredValue?=?false?expectedTypeName?=?null?deferredMethod?=?false?methodSignature?=?null ??
- ????_jspx_th_h3_005finput_005f0.setType( "button" );??
- ???? //?/button2.jsp(12,2)?name?=?onclick?type?=?java.lang.String?reqTime?=?false?required?=?true?fragment?=?false?deferredValue?=?false?expectedTypeName?=?null?deferredMethod?=?false?methodSignature?=?null????_jspx_th_h3_005finput_005f0.setPid("pid"); ??
- ???? //?/button2.jsp(12,2)?name?=?isValidated?type?=?null?reqTime?=?true?required?=?false?fragment?=?false?deferredValue?=?false?expectedTypeName?=?null?deferredMethod?=?false?methodSignature?=?null ??
- ????_jspx_th_h3_005finput_005f0.setIsValidated( "true" );??
- ???? int ?_jspx_eval_h3_005finput_005f0?=?_jspx_th_h3_005finput_005f0.doStartTag();??
- ???? if ?(_jspx_eval_h3_005finput_005f0?!=?javax.servlet.jsp.tagext.Tag.SKIP_BODY)?{??
- ?????? do ?{??
- ????????out.write( "\r\n" );??
- ????????out.write( "\t\t中國人\r\n" );??
- ????????out.write( "\t\t" );??
- ???????? int ?evalDoAfterBody?=?_jspx_th_h3_005finput_005f0.doAfterBody();??
- ???????? if ?(evalDoAfterBody?!=?javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)??
- ?????????? break ;??
- ??????}? while ?( true );??
- ????}??
- ???? if ?(_jspx_th_h3_005finput_005f0.doEndTag()?==?javax.servlet.jsp.tagext.Tag.SKIP_PAGE)?{??
- ??????<span?style= "color:?#ff0000;" >_005fjspx_005ftagPool_005fh3_005finput_0026_005fvalue_005furl_005ftype_005fstyleClass_005fstyle_005fpid_005fonclick_005fname_005fisValidated_005fid.reuse(_jspx_th_h3_005finput_005f0);</span>??
- ?????? return ? true ;??
- ????}??
- <span?style= "color:?#ff0000;" >????_005fjspx_005ftagPool_005fh3_005finput_0026_005fvalue_005furl_005ftype_005fstyleClass_005fstyle_005fpid_005fonclick_005fname_005fisValidated_005fid.reuse(_jspx_th_h3_005finput_005f0);</span>??
- ???? return ? false ;??
- ??}??
最關鍵就是這句了,看他如何獲得自定義標簽對象: tag.InputTag _jspx_th_h3_005finput_005f0 = (tag.InputTag) _005fjspx_005ftagPool_005fh3_005finput_0026_005fvalue_005furl_005ftype_005fstyleClass_005fstyle_005fpid_005fonclick_005fname_005fisValidated_005fid.get(tag.InputTag.class);
解釋下:
?_jspx_th_h3_005finput_005f0 是InputTag 的實例 也就是<h3:input.
而
005fjspx_005ftagPool_005fh3_005finput_0026_005fvalue_005furl_005ftype_005fstyleClass_005fstyle_005fpid_005fonclick_005fname_005fisValidated_005
是TagHandlerPool的實例
?
自定義標簽是通過這個TagHandlerPool.get 來獲取的!
舉一反三,有借就有還TagHandlerPool.reuse用來回收這個對象!
?
?
TagHandlerPool.get?
TagHandlerPool.reuse
方法如下:
?
- /** ?
- ??*?Gets?the?next?available?tag?handler?from?this?tag?handler?pool, ?
- ??*?instantiating?one?if?this?tag?handler?pool?is?empty. ?
- ??* ?
- ??*?@param?handlerClass?Tag?handler?class ?
- ??* ?
- ??*?@return?Reused?or?newly?instantiated?tag?handler ?
- ??* ?
- ??*?@throws?JspException?if?a?tag?handler?cannot?be?instantiated ?
- ??*/ ??
- ? public ?Tag?get(Class?handlerClass)? throws ?JspException?{??
- g?handler?=? null ;??
- ????? synchronized (? this ?)?{??
- ????????? if ?(current?>=? 0 )?{??
- ?????????????handler?=?handlers[current--];??
- ????????????? return ?handler;??
- ?????????}??
- ?????}??
- ??
- ????? //?Out?of?sync?block?-?there?is?no?need?for?other?threads?to ??
- ????? //?wait?for?us?to?construct?a?tag?for?this?thread. ??
- ????? try ?{??
- ?????????Tag?instance?=?(Tag)?handlerClass.newInstance();??
- ?????????AnnotationHelper.postConstruct(annotationProcessor,?instance);??
- ????????? return ?instance;??
- ?????}? catch ?(Exception?e)?{??
- ????????? throw ? new ?JspException(e.getMessage(),?e);??
- ?????}??
- ?}??
?
- /** ?
- ?*?Adds?the?given?tag?handler?to?this?tag?handler?pool,?unless?this?tag ?
- ?*?handler?pool?has?already?reached?its?capacity,?in?which?case?the?tag ?
- ?*?handler's?release()?method?is?called. ?
- ?* ?
- ?*?@param?handler?Tag?handler?to?add?to?this?tag?handler?pool ?
- ?*/ ??
- public ? void ?reuse(Tag?handler)?{??
- ???? synchronized (? this ?)?{??
- ???????? if ?(current?<?(handlers.length?-? 1 ))?{??
- ????????????handlers[++current]?=?handler;??
- ???????????? return ;??
- ????????}??
- ????}??
- ???? //?There?is?no?need?for?other?threads?to?wait?for?us?to?release ??
- ????handler.release();??
- ???? if ?(annotationProcessor?!=? null )?{??
- ???????? try ?{??
- ????????????AnnotationHelper.preDestroy(annotationProcessor,?handler);??
- ????????}? catch ?(Exception?e)?{??
- ????????????log.warn( "Error?processing?preDestroy?on?tag?instance?of?" ???
- ????????????????????+?handler.getClass().getName(),?e);??
- ????????}??
- ????}??
- }??
?
?
現在就明白了所有的tag對象都是有一個對象池來維護的,一是方便了重用,而是做到了線程同步。
?
?總結:自定義標簽是線程安全的,同時也是可重用的!
?
同時又有另一個疑問
?synchronized( this ) {
??????????? if (current >= 0) {
??????????????? handler = handlers[current--];
??????????????? return handler;
??????????? }
??????? }
感覺這種方法可能只能在一個頁面上共享,另一個頁面上的tag估計是不能共享的!
?
后來看了下生成的servelt代碼
如下:
- public ? void ?_jspInit()?{??
- ????_tagpool?=?org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());??
- ????_el_expressionfactory?=?_jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();??
- ????_jsp_annotationprocessor?=?(org.apache.AnnotationProcessor)?getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor. class .getName());??
- ??}??
?可以看到_tagpool 是根據ServletConifg來生成的
TagHandlerPool.getTagHandlerPool代碼如下
- public ? static ?TagHandlerPool?getTagHandlerPool(?ServletConfig?config)?{??
- ???????TagHandlerPool?result= null ;??
- ??
- ???????String?tpClassName=getOption(?config,?OPTION_TAGPOOL,? null );??
- ??????? if (?tpClassName?!=? null ?)?{??
- ??????????? try ?{??
- ???????????????Class?c=Class.forName(?tpClassName?);??
- ???????????????result=(TagHandlerPool)c.newInstance();??
- ???????????}? catch ?(Exception?e)?{??
- ???????????????e.printStackTrace();??
- ???????????????result= null ;??
- ???????????}??
- ???????}??
- ??????? if (?result== null ?)?result= new ?TagHandlerPool();??
- ???????result.init(config);??
- ??
- ??????? return ?result;??
- ???}??
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
