替换属性时 servlet 属性的值
Value of the servlet attribute if the attribute was replaced
这是我正在阅读的书:
Given this code from an otherwise valid HttpServlet that has also been
registered as a ServletRequestAttributeListener:
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
req.setAttribute(“a”, “b”);
req.setAttribute(“a”, “c”);
req.removeAttribute(“a”);
}
public void attributeAdded(ServletRequestAttributeEvent ev) {
System.out.print(“ A:” + ev.getName() + “->” + ev.getValue());
}
public void attributeRemoved(ServletRequestAttributeEvent ev) {
System.out.print(“ M:” + ev.getName() + “->” + ev.getValue());
}
public void attributeReplaced(ServletRequestAttributeEvent ev) {
System.out.print(“ P:” + ev.getName() + “->” + ev.getValue());
}
What logging output is generated?
答案是:
C. A:a->b P:a->b M:a->c
书中的解释是:
Tricky! The getValue method returns the OLD value of the attribute if
the attribute was replaced.
我的问题是这怎么可能?
特别是这部分序列我不清楚:P:a->b
为什么会再次 P:a->b 而不是 P:a->c?
您混淆了 属性 的值和表示属性值已被替换的 事件 的值。
当你打电话给
req.setAttribute("a", "c");
请求创建一个新事件并触发它。所以代码基本上是这样的:
public void setAttribute(String name, Object newValue) {
// 1. get the old value
Object oldValue = getAttribute(name);
// 2. construct an event containing the old value
ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(context, request, name, oldValue);
// 3. store the new value of the attribute
this.attributeMap.put(name, newValue);
// 4. call all the listeners with the event
for (ServletRequestAttributeListener listener : listeners) {
listener.attributeReplaced(event);
}
}
我找到了解释:
The getName() method returns the String name of the attribute that triggered the event. The getValue() method returns the object value of the attribute that triggered the event. Watch out! It returns the old value, not the new one. In other words, it returns the value the attribute had BEFORE the change that triggered the event!
所以它正在做我认为它应该做的事情,只是没有按照我期望的顺序进行(首先更改值然后触发事件)。
更详细的解释是这个:
Just to clarify this output, can we call them "Added", "Replaced" and
"Removed" so we're looking at this:
Added:a->b Replaced:a->b Removed:a->c
Now the question is why does Replaced return "b" for the value instead
of "c"?
The simple answer is because that's what the docs say it should do:
http://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequestAttributeListener.html
void attributeReplaced(ServletRequestAttributeEvent srae) Receives
notification that an attribute has been replaced on the
ServletRequest. Parameters: srae - the ServletRequestAttributeEvent
containing the ServletRequest and the name and (old) value of the
attribute that was replaced
Now maybe the more interesting question is why are they doing this?
Well usually APIs like this are designed to pass you the old value,
because you always have the option to ask for the current value in the
callback. So if they pass you the old value - you have more
information available to you than if they just passed in the current
value. (There's no way to ask "what value did this attribute use to
have?" after it's gone).
So with this API design you could write a listener than took some
action whenever the "a:b" was removed - either by an explicit remove
call or by replacing it with another value. If they only passed in
the new value, you couldn't write that listener (without storing the
values that were added yourself).
Hope that helps make it clearer why it's this way.
这是我正在阅读的书:
Given this code from an otherwise valid HttpServlet that has also been registered as a ServletRequestAttributeListener:
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
req.setAttribute(“a”, “b”);
req.setAttribute(“a”, “c”);
req.removeAttribute(“a”);
}
public void attributeAdded(ServletRequestAttributeEvent ev) {
System.out.print(“ A:” + ev.getName() + “->” + ev.getValue());
}
public void attributeRemoved(ServletRequestAttributeEvent ev) {
System.out.print(“ M:” + ev.getName() + “->” + ev.getValue());
}
public void attributeReplaced(ServletRequestAttributeEvent ev) {
System.out.print(“ P:” + ev.getName() + “->” + ev.getValue());
}
What logging output is generated?
答案是:
C. A:a->b P:a->b M:a->c
书中的解释是:
Tricky! The getValue method returns the OLD value of the attribute if the attribute was replaced.
我的问题是这怎么可能? 特别是这部分序列我不清楚:P:a->b 为什么会再次 P:a->b 而不是 P:a->c?
您混淆了 属性 的值和表示属性值已被替换的 事件 的值。
当你打电话给
req.setAttribute("a", "c");
请求创建一个新事件并触发它。所以代码基本上是这样的:
public void setAttribute(String name, Object newValue) {
// 1. get the old value
Object oldValue = getAttribute(name);
// 2. construct an event containing the old value
ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(context, request, name, oldValue);
// 3. store the new value of the attribute
this.attributeMap.put(name, newValue);
// 4. call all the listeners with the event
for (ServletRequestAttributeListener listener : listeners) {
listener.attributeReplaced(event);
}
}
我找到了解释:
The getName() method returns the String name of the attribute that triggered the event. The getValue() method returns the object value of the attribute that triggered the event. Watch out! It returns the old value, not the new one. In other words, it returns the value the attribute had BEFORE the change that triggered the event!
所以它正在做我认为它应该做的事情,只是没有按照我期望的顺序进行(首先更改值然后触发事件)。
更详细的解释是这个:
Just to clarify this output, can we call them "Added", "Replaced" and "Removed" so we're looking at this:
Added:a->b Replaced:a->b Removed:a->c
Now the question is why does Replaced return "b" for the value instead of "c"?
The simple answer is because that's what the docs say it should do: http://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequestAttributeListener.html
void attributeReplaced(ServletRequestAttributeEvent srae) Receives notification that an attribute has been replaced on the ServletRequest. Parameters: srae - the ServletRequestAttributeEvent containing the ServletRequest and the name and (old) value of the attribute that was replaced
Now maybe the more interesting question is why are they doing this?
Well usually APIs like this are designed to pass you the old value, because you always have the option to ask for the current value in the callback. So if they pass you the old value - you have more information available to you than if they just passed in the current value. (There's no way to ask "what value did this attribute use to have?" after it's gone).
So with this API design you could write a listener than took some action whenever the "a:b" was removed - either by an explicit remove call or by replacing it with another value. If they only passed in the new value, you couldn't write that listener (without storing the values that were added yourself).
Hope that helps make it clearer why it's this way.