`
klcwt
  • 浏览: 189091 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

jsp自定义标签 线程安全

    博客分类:
  • java
阅读更多

我们在编写自定义标签的时候设置属性如下

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
    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.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) {
      _005fjspx_005ftagPool_005fh3_005finput_0026_005fvalue_005furl_005ftype_005fstyleClass_005fstyle_005fpid_005fonclick_005fname_005fisValidated_005fid.reuse(_jspx_th_h3_005finput_005f0);
      return true;
    }
    _005fjspx_005ftagPool_005fh3_005finput_0026_005fvalue_005furl_005ftype_005fstyleClass_005fstyle_005fpid_005fonclick_005fname_005fisValidated_005fid.reuse(_jspx_th_h3_005finput_005f0);
    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 {
	Tag 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;
    }

 

 

分享到:
评论
3 楼 shuaijie506 2016-12-17  
以前有点疑惑,现在终于明白了,线程安全是没问题的,想想也是,如果有问题的话就是超级大bug了,现在终于明白实现的原理了。
2 楼 Laster2800 2016-12-05  
原来如此,想不到传统的标记处理器也是线程安全的,受教了。
1 楼 wellse 2014-04-29  
呵呵,就是这样!!要的就是这个效果

相关推荐

    JSP和Servlet面试题

    线程安全就是多线程操作同一个对象不会有问题,线程同步一般来保护线程安全, 所以可以在Servlet的线程里面加上同步方法或同步块。 (Synchronized)可以保证在同一时间只有一个线程访问,(使用同步块会导致性能...

    java视频教程Day01 免费

    31. Custom Tags I (自定义标签I) 32. Java Standard Tag Library (标准标签库) 33. Expression Language(表达式语言) 34. Expression Language(表达式语言) 35. 使用Java WEB技术编写网页QQ J2EE 框架...

    从J2SE到J2EE知识点介绍

    (三) Jsp基本页面标签 116 1. 标签 116 2. contentType属性 118 3. pageEncoding属性 118 (四) form表单中的action,post和get 119 1. form中的action属性 119 2. from中的get和post 120 (五) jsp内置对象(request,...

    s2m企业级整站系统 v4.0.0

    插件管理功能,支持多插件管理[新增] 每个页面可自定义,设置页面模板[改进] 重写验证码模块代码[新增] 考虑到安全性能,系统禁止了浏览器直接访问jsp页面运行[改进] httpUtils 组件增加1分钟超时,防止无限期等待...

    java必了解的六大问题

    *第十一阶段:JSP开发:JSP语法和标签,自定义标签,EL,JSTL库了解以及MVC三层架构的设计模式理念; *第十二阶段:AJAX开发:AJAX原理,请求响应处理,AJAX开发库; *第十三阶段:轻量级框架,三大框架之一...

    超级有影响力霸气的Java面试题大全文档

    HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。 HashMap允许将null作为一个entry的key或者...

    B3LOG Solo v1.0.0 for MySQL.zip

    169 DateFormat 线程安全问题 170 登录页面底部链接问题 172 GAE 版配额消耗过快问题 177 泄漏用户密码安全问题 129 摘要编辑器添加源码功能 132 Markdown 编辑器显示问题 154 使用密文存储密码 155 邮件 SSL...

    s2m企业级整站系统 v4.0.0.zip

    [新增] 考虑到安全性能,系统禁止了浏览器直接访问jsp页面运行 [改进] httpUtils 组件增加1分钟超时,防止无限期等待 [改进] 定时任务修改为支持多线程,多任务并行运行 s2m企业级整站系统如何安装 下载后,将 ...

    J2EE面试题

    11) 编写自定义标签处理类后,需要编写一个()去描述。 a) .tag 文件 b) .tld 文件 c) .dtd文件 d) .xml 文件 12) 关于Tag File说法不正确的是()。 a) Tag File是JSP2.0新增的功能 b) Tag File是JSP...

    Java开发技术大全(500个源代码).

    ThreadImRunnable.java 继承Runnable接口实现多线程 mulThread.java 创建多个线程对象的类 demoJoin.java 演示使用join()以确保主线程最后结束 clicker.java 一个计数用的线程类 demoPri.java 调用上面这个类...

    java初学者必看

    4.4.3 标签语句 4.5 返回语句 4.6 综合实例:水仙花数 4.7 本章习题 第5章 字符串 5.1 字符串简介 5.1.1 字符串常量 5.1.2 String创建字符串常量 5.1.3 StringBuffer创建字符串 5.2 连接字符串 5.2.1 与...

    淘特大型门户网站CMS企业版

    5、支持自定义标签管理,可以灵活定制多种显示效果。 6、文章、栏目模板支持。 7、基于角色的管理机制 8、搜索采用Lucene索引技术,支持任务管理,搜索速度相当于百度、GOOGLE 9、系统自带数据库连接池,性能...

    java面试题

    Collections是针对集合类的帮助类,它提供了一系列针对集合的搜索,排序,线程安全化等操作。 final、finally、finalize的区别? 答:final用于声明属性方法和类,分别表示:属性不可变,方法不可覆盖,类不可继承...

    Tomcat监控工具Probe,支持tomcat6-7-8-9.zip

    Threads:tomcat线程,可以查看线程的状态等信息,还可以杀死线程 Cluster:tomcat集群 System Information:系统信息 Connectors:connector信息,可以看到每秒的请求数、响应时间等 Quick check:...

    facelets-lite:小面精简版

    它非常适合将HTML片段包装为自定义标签并在以后重用。 今天,这个美丽的宝石隐藏在J2EE堆栈的深处。 Facelets精简版实现剥离了所有J2EE / JSF依赖项的Facelets。 它提供了一个简单,干净且简单的库,同时保留并...

    Java语言基础下载

    自定义标签 613 标准标签的使用 618 内容总结 621 独立实战 622 第三十章:struts入门 623 学习目标 623 Struts简介 624 什么是应用框架 624 WEB框架所要解决的问题 625 建立简单的Struts应用 627 内容总结 636 独立...

    Java2实用教程.rar

    4 16 2自定义异常类 4 17Class类 4 17 1获取类的有关信息 4 17 2使用Class实例化一个对象 4 18基本类型的类包装 4 18 1Double类和Float类 4 18 2Byte Integer Short 工 ong类 4 18 3Character类 4 19反编译和文档...

    IBM WebSphere Portal门户开发笔记01

    14、JSP中初始化workspace的标签 78 15、JSP中用标签输出一条内容 78 (二)、标签及其功能的使用 78 1、Writing links to Web Content Management content 78 (三)拖放 JSP标记 80 1)&lt;dnd:drag/&gt; 80 2)...

    java 面试题 总结

    HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。 HashMap允许将null作为一个entry的key或者...

    Java开发技术大全 电子版

    14.8.1标签(Jlabel)使用示例488 14.8.2按钮(JButton)使用示例491 14.8.3文本框(JTextField)和密码框(JPasswordField)使用示例492 14.8.4文本区(JTextArea)使用示例496 14.8.5复选框(JcheckBox)使用...

Global site tag (gtag.js) - Google Analytics