首页 > 代码库 > 同一Page范围内多个相同自定义标签类实例化个数相关问题阐述
同一Page范围内多个相同自定义标签类实例化个数相关问题阐述
问题描述:(jsp自定义标签代码片段中出现出来多个相同类型的标签<JB:ToobarCellComponent。那么jsp引擎是否实例化多个标签对象呢)那么大家可能就奇怪了,研究这个问题到底对我们项目研发有何好处呢?其实这个问题可以延伸出很多关于java自定义标签的一些高级应用以及自定义标签的解析原理,比如自定义标签按钮级别的权限控制【页面控件权值记录,初始化等】等。研究这些设计框架大有所益处,以下内容但愿对你有所帮助。也欢迎大家进入群【376447127】与我交流RAD快速开发平台相关技术。
<JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="button" btnSelectName="新增" imgDisabled="plus.gif" imgEnabled="plus.gif" itemId="0" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="separator" imgDisabled="" imgEnabled="" itemId="1" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="button" btnSelectName="保存" imgDisabled="save.gif" imgEnabled="save.gif" itemId="2" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="separator" imgDisabled="" imgEnabled="" itemId="3" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="button" btnSelectName="删除" imgDisabled="delete.gif" imgEnabled="delete.gif" itemId="4" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="separator" imgDisabled="" imgEnabled="" itemId="5" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="button" btnSelectName="隐藏/关闭" imgDisabled="sysset.gif" imgEnabled="sysset.gif" itemId="6" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="separator" imgDisabled="" imgEnabled="" itemId="7" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="button" btnSelectName="刷新" imgDisabled="refresh.gif" imgEnabled="refresh.gif" itemId="8" optionItems=""></JB:ToolBarCellComponent> <JB:ToolBarCellComponent id="skinSetting_Toolbar" cellType="separator" imgDisabled="" imgEnabled="" itemId="9" optionItems=""></JB:ToolBarCellComponent>像以上这段jsp自定义标签代码片段中出现出来多个相同类型的标签<JB:ToobarCellComponent。那么jsp引擎是否实例化多个标签对象呢?这个问题是接下里需要考究的!
对于以上其中一个标签对应执行的相关操作我们可以通过查看jsp引擎编译整合jsp页面生成servlet类中一个方法,代码如下:
private boolean _jspx_meth_JB_005fToolBarCellComponent_005f6(javax.servlet.jsp.tagext.JspTag _jspx_th_JB_005fToolBarComponent_005f0, PageContext _jspx_page_context) throws Throwable { PageContext pageContext = _jspx_page_context; JspWriter out = _jspx_page_context.getOut(); // JB:ToolBarCellComponent org.jplogic.system.core.soa.component.taglib.ToolBarCellControl _jspx_th_JB_005fToolBarCellComponent_005f6 = (org.jplogic.system.core.soa.component.taglib.ToolBarCellControl) _005fjspx_005ftagPool_005fJB_005fToolBarCellComponent_0026_005foptionItems_005fitemId_005fimgEnabled_005fimgDisabled_005fid_005fcellType_005fbtnSelectName_005fnobody.get(org.jplogic.system.core.soa.component.taglib.ToolBarCellControl.class); _jspx_th_JB_005fToolBarCellComponent_005f6.setPageContext(_jspx_page_context); _jspx_th_JB_005fToolBarCellComponent_005f6.setParent((javax.servlet.jsp.tagext.Tag)_jspx_th_JB_005fToolBarComponent_005f0); // /jsp/JpSystem/SystemParamConfigMngForm.jsp(342,6) name = id type = null reqTime = true required = true fragment = false deferredValue = http://www.mamicode.com/false expectedTypeName = null deferredMethod = false methodSignature = null>通过以上代码你可以了解到在在jsp1.2规范中:(大家有兴趣可以去查看一下,可以很方便的让你了解到自定义标签技术的相关执行过程)
1:当容器创建一个新的标签实例后,通过setPageContext设置标签的页面上下文。
2:使用setParent方法设置这个标签的上一级标签。如果没有上一级嵌套,设置为空。
3:设置标签的属性。这个属性在标签库描述文件中定义。如果没有定义属性就不调用此类方法。
4:调用 doStartTag方法,这个方法可以返回EVAL_BODY_INCLUDE和SKIP_BODY。当返回EVAL_BODY_INCLUDE时,就计算标签的BODY,如果返回SKIP_BODY,就 不计算标签的BODY。
5:调用doEndTag方法,这个方法可以返回EVAL_PAGE或者SKIP_PAGE。当返回EVAL_PAGE时,容器将在标签结束时继续计算JSP页面的其他部分;如果返回SKIP_PAGE,容器将在标签结束时停止计算JSP页面的其他部分。6:调用release方法释放标签程序占用的任何资源。
jsp引擎编译后的servlet类中看到标签对象引用:
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fJB_005fToolBarCellComponent_0026_005foptionItems_005fitemId_005fimgEnabled_005fimgDisabled_005fid_005fcellType_005fbtnSelectName_005fnobody;
当我们阅读这个有jsp引擎编译后的servlet的源代码可以看出,我们标签对象实例是通过标签处理对象池来获取,调用标签处理对象池TagHandlerPool类的get方法来获取相应的标签处理对象。入参为相应标签处理对象的class.。下面我们来看看这个jsp引擎编译后的servlet是如何通过TagHandlerPool来获取具体的标签处理对象的。
类TagHandlerPool内部代码如下:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jasper.runtime; import javax.servlet.ServletConfig; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; import org.apache.jasper.Constants; import org.apache.tomcat.InstanceManager; import org.jboss.logging.Logger; /** * Pool of tag handlers that can be reused. * * @author Jan Luehe */ public class TagHandlerPool { private Tag[] handlers; public static final String OPTION_TAGPOOL="tagpoolClassName"; public static final String OPTION_MAXSIZE="tagpoolMaxSize"; // index of next available tag handler private int current; protected InstanceManager instanceManager = null; 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) { result = null; } } <strong><span style="color:#ff0000;">if( result==null ) result=new PerThreadTagHandlerPool();</span> <span style="color:#ff0000;"> result.init(config);</span></strong> return result; } protected void init( ServletConfig config ) { int maxSize=-1; String maxSizeS=getOption(config, OPTION_MAXSIZE, null); if( maxSizeS != null ) { try { maxSize=Integer.parseInt(maxSizeS); } catch( Exception ex) { maxSize=-1; } } if( maxSize <0 ) { maxSize=Constants.MAX_POOL_SIZE; } this.handlers = new Tag[maxSize]; this.current = -1; instanceManager = InstanceManagerFactory.getInstanceManager(config); } /** * Constructs a tag handler pool with the default capacity. */ public TagHandlerPool() { // Nothing - jasper generated servlets call the other constructor, // this should be used in future + init . } /** * Constructs a tag handler pool with the given capacity. * * @param capacity Tag handler pool capacity * @deprecated Use static getTagHandlerPool */ public TagHandlerPool(int capacity) { this.handlers = new Tag[capacity]; this.current = -1; } /** * 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 { Tag handler; 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 { if (Constants.USE_INSTANCE_MANAGER_FOR_TAGS) { return (Tag) instanceManager.newInstance(handlerClass); } else { Tag instance = (Tag) handlerClass.newInstance(); if (Constants.INJECT_TAGS) { instanceManager.newInstance(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 (Constants.INJECT_TAGS || Constants.USE_INSTANCE_MANAGER_FOR_TAGS) { try { instanceManager.destroyInstance(handler); } catch (Exception e) { // Ignore } } } /** * Calls the release() method of all available tag handlers in this tag * handler pool. */ public synchronized void release() { for (int i = current; i >= 0; i--) { handlers[i].release(); if (Constants.INJECT_TAGS || Constants.USE_INSTANCE_MANAGER_FOR_TAGS) { try { instanceManager.destroyInstance(handlers[i]); } catch (Exception e) { // Ignore } } } } protected static String getOption( ServletConfig config, String name, String defaultV) { if( config == null ) return defaultV; String value=http://www.mamicode.com/config.getInitParameter(name);>通过以上源码可以看出
if
( result==
null
) result=
new
PerThreadTagHandlerPool();
result.init(config);
下面我们再来看看PerThreadTagHandlerPool类中的两个方法:
protected void init(ServletConfig config) { instanceManager = InstanceManagerFactory.getInstanceManager(config); maxSize = Constants.MAX_POOL_SIZE; String maxSizeS = getOption(config, OPTION_MAXSIZE, null); if (maxSizeS != null) { maxSize = Integer.parseInt(maxSizeS); if (maxSize < 0) { maxSize = Constants.MAX_POOL_SIZE; } } perThread = new ThreadLocal<PerThreadData>() { protected PerThreadData initialValue() { PerThreadData ptd = new PerThreadData(); ptd.handlers = new Tag[maxSize]; ptd.current = -1; perThreadDataVector.addElement(ptd); return ptd; } }; } /** * 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 { PerThreadData ptd = (PerThreadData)perThread.get(); if(ptd.current >=0 ) { return ptd.handlers[ptd.current--]; } else { try { if (Constants.USE_INSTANCE_MANAGER_FOR_TAGS) { return (Tag) instanceManager.newInstance(handlerClass); } else { Tag instance = (Tag) handlerClass.newInstance(); if (Constants.INJECT_TAGS) { instanceManager.newInstance(instance); } return instance; } } catch (Exception e) { throw new JspException(e.getMessage(), e); } } }从以上代码可以看出PerThreadTagHandlerPool继承类TagHandlerPool,jsp引擎编译后的servlet首选通过PerThreadTagHandlerPool的get方法获取相应标签处理对象实例(首先判断线程池中是否存在需要的标签处理对象实例,如果存在直接返回,不存在的话,通过上下文以及反射来创建新的标签处理对象)。那么以上提出的jsp自定义标签代码片段中出现出来多个相同类型的标签<JB:ToobarCellComponent。那么jsp引擎是否实例化多个标签对象呢?问题的答案就很清楚了!该篇文章回答http://www.iteye.com/problems/30505链接提出的问题。
同一Page范围内多个相同自定义标签类实例化个数相关问题阐述