| |||||||||||||||||||||||||||||||||
Find this tutorial in: /usr/local/resin/webapps/resin-doc/jsp/tutorial/taglib-reuse
Try the Tutorial Tag libraries must follow important conventions for initializing tag fields. The JSP specification lets a JSP container, like Resin, reuse tag handler instances for efficiency and performance. Because this optimization restricts how tags can use fields, even experienced developers will benefit from this tutorial.
Resin aggressively reuses tag handler instances. Any tag with the same set of attributes is a candidate for reuse. For example, a tag <msg:message> with an attribute title="Test-1" may share the same tag handler instance as a <msg:message> with an attribute title="Test-2". This ability for Resin to reuse instances of the tag handler is described in the JSP specification. From the JSP 2.0 specification: "The JSP container may reuse classic tag handler instances for multiple occurrences of the corresponding custom action, in the same page or in different pages, but only if the same set of attributes are used for all occurrences." In this tutorial, the <msg:message> prints its id to show the instance of the object that is created.
The instance created for the first <msg:message> tag, MessageTag@10000, is reused for the third <msg:message> tag. Resin can reuse the tag handler instance the attributes set for the first and third objects are the same: {title}. The second tag uses a new instance, MessageTag@100000, because it has a different attribute set: {text}.
Lifecycle
Resin does not call release() between the first and third <msg:message> tags. It only calls release() at the end of the page. This behavior follows the JSP spec, but surprises some tag library developers.
Since tag handler instances are reused, the fields corresponding to tag attributes must be read-only. Only Resin may call the attribute setters; the tag's code must never modify the corresponding fields.
Tags must initialize internal variables in the first action method called, for example doStartTag. Because of tag instance reuse, the tag must assume that all internal variables are unset, i.e. set to unknown, bogus values. The initialization code must initialize those values. Often in a tag it is necessary to have additional member variables other than those that hold the value of tag attributes. In this case, the only safe way to initialize the variables is in the doStartTag(), before anything else is done. Because the tag instance will be reused, you cannot simply initialize the tag in the constructor. And, because the release() method is only called at the end of the page, the tag cannot call initialization code in the release() method. There may be many calls to doStartTag() and doEndTag() before release() is called. In this tutorial, an init() method is used for initialization of these internal member variables, and a call to init() is the first thing done in doStartTag().
Tag libraries need to initialize their variables in the first tag method called. Most often, this will be in doStartTag, but some tags only implement doEndTag. Tags which only have a doEndTag may initialize in doEndTag. Because Resin can analyze which methods are implemented by a tag and generated better code for the default TagSupport methods, it's a good idea to only implement those tag methods which are absolutely necessary.
If an attribute of a tag is not used, the corresponding setter will not be called. In many causes you will want to provide a default value for the attribute, and then the default value will be dependent on other member variables. Even though it is not always necessary, the best way to set a default value for a missing attribute is the same way the internal member variables are set in the previous example.
|