准備工作:xwork源碼一份(我的版本是2.0.4)。
1.當時我是這么建立這個類的
- public class StaticAction extends ActionSupport {
- static {
- logDir = ServletActionContext.getServletContext().getRealPath("/"); //在這里打個斷點
- }
- }
2.在com.opensymphony.xwork2.DefaultActionInvocation 類下大約第362行
- private void init() throws Exception {
- Map contextMap = createContextMap();
- createAction(contextMap); //在這個方法打個斷點,該方法會去創建你所調用的Action。詳情可以看看它里面的objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);這一句
- if (pushAction) {
- stack.push(action);
- }
- invocationContext = new ActionContext(contextMap); //注意你所調用的Action,它的ActionContext在這里才會創建。
- invocationContext.setName(proxy.getActionName());
- // get a new List so we don't get problems with the iterator if someone changes the list
- List interceptorList = new ArrayList(proxy.getConfig().getInterceptors());
- interceptors = interceptorList.iterator();
- }
好了。調試運行。因為StaticAction有靜態代碼塊,而objectFactory在創建action實例時,使用的是Class.forName(String cls)方式,它的具體實現如下:
- java.lang.Class.java
- public static Class<?> forName(String className)
- throws ClassNotFoundException {
- return forName0(className, true, ClassLoader.getCallerClassLoader());
- }
看到forName0的第二個參數設置為true了嗎?表示該類被JVM裝載后,要不要立即初始化,如果設置成false,表示在將初始化的工作推遲到了newInstance的時候進行.所以,當方法createAction(contextMap)被調用時,要執行的StaticAction的靜態代碼塊肯定會被調用的。
當運行到ServletActionContext.getServletContext().getRealPath("/")這一句時,繼續查看ServletActionContext.getServletContext()的來源:
org.apache.struts2.ServletActionContext.java 大概第137行
- public static ServletContext getServletContext() {
- return (ServletContext) ActionContext.getContext().get(SERVLET_CONTEXT);
- }
可以看到其實調用的是ActionContext.getContext().get(SERVLET_CONTEXT);過來的,而咱們在最開始也看到了createAction(contextMap);方法在 invocationContext = new ActionContext(contextMap); 方法執行之前,是無法正常得到SERVLET_CONTEXT的,所以,就會出空指針異常了。

