在创建 JSP-Tags 时,我有时会创建一个属性“id”来设置所创建元素的 element-id。对于那个 id,我还创建了一个 setter。现在我发现 TagSupport 已经有一个属性“id”和它的专用设置器,我覆盖了那个方法。
到目前为止,它对我的应用程序没有负面影响,但是任何人都可以告诉我该 id 的用途以及覆盖它时会出现什么问题?
有趣的问题
如果你查看 TagSupport 的源代码,你会发现原来的 setId/getId 方法只是 getter 和 setter:
protected String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
在该类中,只有一种方法直接调用 id 字段:
public void release() {
parent = null;
id = null;
if( values != null ) {
values.clear();
}
values = null;
}
该方法来自 Tag 接口:
public interface Tag extends JspTag {
...
/**
* Called on a Tag handler to release state.
* The page compiler guarantees that JSP page implementation
* objects will invoke this method on all tag handlers,
* but there may be multiple invocations on doStartTag and doEndTag in between.
*/
void release();
...
}
如果我们假设其他内部类使用 get/set 方法(而不是字段访问)来访问这个 id 属性,那么只有一个地方需要担心(这个释放方法)。
JSP 规范声明: “JSP 容器可以在同一页面或不同页面中针对相应自定义操作的多次出现重用经典标记处理程序实例,但前提是所有出现都使用相同的属性集。”
我认为唯一可能导致一些问题的情况是当您有两个标签时,一个带有 id,另一个没有 id,并且容器重用标签实例。
测试用例:
标记类:
public class TestTag extends TagSupport {
protected String id;
static int count = 0;
int instanceNuber=0;
public TestTag() {
super();
System.out.println("TestTag.TestTag() - new Instance");
instanceNuber = ++count;
}
@Override
public int doStartTag() throws JspException {
JspWriter out = pageContext.getOut();
try {
out.print("id = " + getIdWrapper());
} catch (IOException e) {
}
return (SKIP_BODY);
}
public String getIdWrapper() {
return getId();
}
@Override
public String getId() {
System.out.println("Instance " + instanceNuber + " of TestTag.getId() = " + id);
return id;
}
@Override
public void setId(String id) {
System.out.println("Instance " + instanceNuber + " of TestTag.setId(" + id + ")");
this.id = id;
}
}
JSP:
<my:test id="dog"/>
<br/>
<my:test/>
<br/>
<my:test id="cat"/>
<br/>
<my:test/>
<br/>
印刷:
id = dog
id = null
id = cat
id = null
我在tomcat 7下测试了这个,clonsole输出是:
TestTag.TestTag() - new Instance <- new instance for first occurance of tag with id
Instance 1 of TestTag.setId(dog)
Instance 1 of TestTag.getId() = dog
TestTag.TestTag() - new Instance <- new instance for first occurance of tag without id
Instance 2 of TestTag.getId() = null
Instance 1 of TestTag.setId(cat) <- reuse of instance 1
Instance 1 of TestTag.getId() = cat
Instance 2 of TestTag.getId() = null <- reuse of instance 2
回答你的问题
看起来只有当所有事件都使用相同的一组属性时,tomcat才会重用经典标记处理程序实例。无论属性集看起来如何,其他容器都可以为同一页面上的所有标签重用实例。
因此,在 Tomcat 下,对您的应用程序没有负面影响,因为您有 2 个实例(在我的情况下)。一个用于具有 id 的标签,另一个用于相同的标签但没有 id(给定属性集的一个标签实例)。所以不用担心页面上的某些标签会从以前使用的实例中继承一些“旧”id。
但是在其他容器而不是输出上:
id = dog
id = null
id = cat
id = null
你可以得到:
id = dog
id = dog
id = cat
id = cat
因此,如果您的代码取决于这些 id。覆盖此 setId/getId 方法可能会导致某些容器出现问题并且难以找到错误。
所以不要覆盖这个 setId/getId 方法。
还有一件事。不要使用经典标签,这是旧的 API。使用 SimpleTagSupport。