Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- Keep-Alive
- singleton
- reflection
- toString
- object
- Session
- getRequestURI
- Transfer-Encoding
- http
- unmodifiableList
- clone
- InvocationHandler
- Content-Length
- Proxy
- Reference
- chunked
- http/1.1
- Java
- cookie
- urlclassloader
Archives
- Today
- Total
pungjoo
Failed to invoke last-modified method - springframework 본문
인지
Failed to invoke last-modified method 발생하며 StackOverFlow 발생.
일반적인 해결 방안
왜 그럴까?
위와 같이 get이라는 method로 설정하게되면 내부적으로 'Recurrsive'가 발생하게 되어 종국에는 'Failed to invoke last-modified method'라는 메시지 발생.
분석
우선 org/springframework/web/servlet/mvc/multiaction/MultiActionController.java의 registerLastModifiedMethodIfExists
method.getName() + LAST_MODIFIED_METHOD_SUFFIX 부분만 보고 생각해 보면 method의 객체가 get이라고 볼때 get에 LAST_MODIFIED_METHOD_SUFFIX인 LastModified를 조합해 getLastModified method 객체를 map에 넣게 됩니다.
즉, 애초의 의도는 사용자 actionController class에 getXXXLastModified(..)라는 method가 존재하면 존재하는 method를 map에 넣고 그렇지 않으면 skip하는 구조인데 잘못된 action mapping으로 아래 언급하는 getLastModified method 객체를 추가하게되고, springframework의 본래 getLastModified method를 call method로 넣는 바람에 재귀호출이 일어나는 구조적 문제를 야기합니다.
org/springframework/web/servlet/mvc/multiaction/MultiActionController.java의 getLastModified
위와 같은 상황에서 getLastModified(..) 호출이 발생했고 해당 request의 handlerMethodName이 get이라고 한다면 결국에 lastModifiedMethod은 getLastModifiedMethod가 되며 이 method는 위에서 언급 했듯이 지금 유입된 자기 자신이므로 재귀호출하게됩니다.. 무한 반복...
참고
만약 제니퍼를 사용하고 있다면 위 case를 'Infinite Recurrsive Call indicated'로 인지하게 되며 'active Thread' 상에 종료되지 않은 요청으로 남게 됩니다.
위 case를 인지하기 전까지 'Infinite Recurrsive Call indicated'에 대해서 RequestDispatcher의 forward()/ include()의 무한반복재귀호출로 생각하고 문제 없는 소스만 검토를 했었습니다.
@
Failed to invoke last-modified method 발생하며 StackOverFlow 발생.
일반적인 해결 방안
@Override
public long getLastModified(HttpServletRequest request) {
return -1;
}
public long getLastModified(HttpServletRequest request) {
return -1;
}
왜 그럴까?
<bean id="xxxMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<props>
<prop key="/xxx.abc">get</prop>
</props>
</property>
</bean>
<property name="mappings">
<props>
<prop key="/xxx.abc">get</prop>
</props>
</property>
</bean>
위와 같이 get이라는 method로 설정하게되면 내부적으로 'Recurrsive'가 발생하게 되어 종국에는 'Failed to invoke last-modified method'라는 메시지 발생.
분석
우선 org/springframework/web/servlet/mvc/multiaction/MultiActionController.java의 registerLastModifiedMethodIfExists
private void registerLastModifiedMethodIfExists(Object delegate, Method method) {
// Look for corresponding LastModified method.
try {
Method lastModifiedMethod = delegate.getClass().getMethod(
method.getName() + LAST_MODIFIED_METHOD_SUFFIX,
new Class[] {HttpServletRequest.class});
// Put in cache, keyed by handler method name.
this.lastModifiedMethodMap.put(method.getName(), lastModifiedMethod);
if (logger.isDebugEnabled()) {
logger.debug("Found last modified method for action method [" + method + "]");
}
}
catch (NoSuchMethodException ex) {
// No last modified method. That's ok.
}
}
// Look for corresponding LastModified method.
try {
Method lastModifiedMethod = delegate.getClass().getMethod(
method.getName() + LAST_MODIFIED_METHOD_SUFFIX,
new Class[] {HttpServletRequest.class});
// Put in cache, keyed by handler method name.
this.lastModifiedMethodMap.put(method.getName(), lastModifiedMethod);
if (logger.isDebugEnabled()) {
logger.debug("Found last modified method for action method [" + method + "]");
}
}
catch (NoSuchMethodException ex) {
// No last modified method. That's ok.
}
}
method.getName() + LAST_MODIFIED_METHOD_SUFFIX 부분만 보고 생각해 보면 method의 객체가 get이라고 볼때 get에 LAST_MODIFIED_METHOD_SUFFIX인 LastModified를 조합해 getLastModified method 객체를 map에 넣게 됩니다.
즉, 애초의 의도는 사용자 actionController class에 getXXXLastModified(..)라는 method가 존재하면 존재하는 method를 map에 넣고 그렇지 않으면 skip하는 구조인데 잘못된 action mapping으로 아래 언급하는 getLastModified method 객체를 추가하게되고, springframework의 본래 getLastModified method를 call method로 넣는 바람에 재귀호출이 일어나는 구조적 문제를 야기합니다.
org/springframework/web/servlet/mvc/multiaction/MultiActionController.java의 getLastModified
/**
* Try to find an XXXXLastModified method, where XXXX is the name of a handler.
* Return -1, indicating that content must be updated, if there's no such handler.
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified(HttpServletRequest)
*/
public long getLastModified(HttpServletRequest request) {
try {
String handlerMethodName = this.methodNameResolver.getHandlerMethodName(request);
Method lastModifiedMethod = (Method) this.lastModifiedMethodMap.get(handlerMethodName);
if (lastModifiedMethod != null) {
try {
// invoke the last-modified method
Long wrappedLong = (Long) lastModifiedMethod.invoke(this.delegate, new Object[] { request });
return wrappedLong.longValue();
}
catch (Exception ex) {
// We encountered an error invoking the last-modified method.
// We can't do anything useful except log this, as we can't throw an exception.
logger.error("Failed to invoke last-modified method", ex);
}
} // if we had a lastModified method for this request
}
catch (NoSuchRequestHandlingMethodException ex) {
// No handler method for this request. This shouldn't happen, as this
// method shouldn't be called unless a previous invocation of this class
// has generated content. Do nothing, that's OK: We'll return default.
}
return -1L;
}
* Try to find an XXXXLastModified method, where XXXX is the name of a handler.
* Return -1, indicating that content must be updated, if there's no such handler.
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified(HttpServletRequest)
*/
public long getLastModified(HttpServletRequest request) {
try {
String handlerMethodName = this.methodNameResolver.getHandlerMethodName(request);
Method lastModifiedMethod = (Method) this.lastModifiedMethodMap.get(handlerMethodName);
if (lastModifiedMethod != null) {
try {
// invoke the last-modified method
Long wrappedLong = (Long) lastModifiedMethod.invoke(this.delegate, new Object[] { request });
return wrappedLong.longValue();
}
catch (Exception ex) {
// We encountered an error invoking the last-modified method.
// We can't do anything useful except log this, as we can't throw an exception.
logger.error("Failed to invoke last-modified method", ex);
}
} // if we had a lastModified method for this request
}
catch (NoSuchRequestHandlingMethodException ex) {
// No handler method for this request. This shouldn't happen, as this
// method shouldn't be called unless a previous invocation of this class
// has generated content. Do nothing, that's OK: We'll return default.
}
return -1L;
}
위와 같은 상황에서 getLastModified(..) 호출이 발생했고 해당 request의 handlerMethodName이 get이라고 한다면 결국에 lastModifiedMethod은 getLastModifiedMethod가 되며 이 method는 위에서 언급 했듯이 지금 유입된 자기 자신이므로 재귀호출하게됩니다.. 무한 반복...
참고
만약 제니퍼를 사용하고 있다면 위 case를 'Infinite Recurrsive Call indicated'로 인지하게 되며 'active Thread' 상에 종료되지 않은 요청으로 남게 됩니다.
위 case를 인지하기 전까지 'Infinite Recurrsive Call indicated'에 대해서 RequestDispatcher의 forward()/ include()의 무한반복재귀호출로 생각하고 문제 없는 소스만 검토를 했었습니다.
@
Comments