首页 > 代码库 > 同一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=newPerThreadTagHandlerPool();

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范围内多个相同自定义标签类实例化个数相关问题阐述