ControlServlet.java 这是一个servlet,其配置文件在web.xml里
<servlet>
<servlet-name>ControlServlet</servlet-name>
<display-name>ControlServlet</display-name>
<description>MainControl Servlet</description>
<servlet-class>org.apache.ofbiz.webapp.control.ControlServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ControlServlet</servlet-name>
<url-pattern>/control/*</url-pattern>
</servlet-mapping>
这也是为什么大多数请求都是组件名/control/*
首先在第一次请求时经过Servlet的init方法,该Servlet方法如下:
public void init(ServletConfig config) throws ServletException {
super.init(config);
if (Debug.infoOn()) {
ServletContext servletContext = config.getServletContext();
String webappName = servletContext.getContextPath().length() != 0 ?servletContext.getContextPath().substring(1) : "";
Debug.logInfo("Loading webapp [" + webappName + "],located at " + servletContext.getRealPath("/"), module);
}
//配置默认脚本引擎,默认有beanshell和平台自定义的minilang脚本,可扩展其它脚本
configureBsf();
// 初始化request处理句柄,实质就是加载controller.xml中handler节点中class属性值对应类的实例化和初始化
getRequestHandler();
}
该方法中的getRequestHandler就是获取所有的handler节点,加载方式如下
/**
* @Title: getRequestHandler
* @Description: 获取request的处理句柄,request处理分两类,一类是view,
* 另一类是event,对应controller.xml中handler节点的配置信息的获取
* @return: RequestHandler
*/
protected RequestHandler getRequestHandler() {
return RequestHandler.getRequestHandler(getServletContext());
}
/**
* @Title: getRequestHandler
* @Description: 在上下文中新建一个requesthandler,命名为_REQUEST_HANDLER_,
* 构造方法为private,此方法共外界获取实例,为单例模式使用,requesthandler配置来至
* 处理controller.xml中handler节点的配置数据
* @param servletContext
* @return: RequestHandler
*/
public static RequestHandler getRequestHandler(ServletContextservletContext) {
RequestHandler rh = (RequestHandler)servletContext.getAttribute("_REQUEST_HANDLER_");
if (rh == null) {
rh = newRequestHandler(servletContext);
servletContext.setAttribute("_REQUEST_HANDLER_", rh);
}
return rh;
}
其中的RequestHandler方法如下
/**
* @author jack
* 第一步:将controller.xml的解析信息加入到缓存中
* */
private RequestHandler(ServletContext context) {
// init the ControllerConfig, but don't save it anywhere, just load itinto the cache
this.controllerConfigURL = ConfigXMLReader.getControllerConfigURL(context);
try {
//将controller.xml的解析信息加入到缓存中
ConfigXMLReader.getControllerConfig(this.controllerConfigURL);
} catch (WebAppConfigurationException e) {
// FIXME: controller.xml errors should throw an exception.
Debug.logError(e, "Exception thrown while parsing controller.xmlfile: ", module);
}
//加载ViewHandler实现类的实例,其为controller.xml中handler的类型为view
this.viewFactory = new ViewFactory(context,this.controllerConfigURL);
//加载EventHandler实现类的实例,其为controller.xml中handler的类型为非view的情况
this.eventFactory = new EventFactory(context, this.controllerConfigURL);
this.forceHttpSession ="true".equalsIgnoreCase(context.getInitParameter("forceHttpSession"));
this.trackServerHit =!"false".equalsIgnoreCase(context.getInitParameter("track-serverhit"));
this.trackVisit =!"false".equalsIgnoreCase(context.getInitParameter("track-visit"));
this.cookies = !"false".equalsIgnoreCase(context.getInitParameter("cookies"));
this.charset = context.getInitParameter("charset");
}
其具体存储方式如下
/**
* @author jack
* 构建ViewHandler实现类的map,对handler节点的class属性值对应的类进行实例化和初始化,
* 并设置key=default时,其value=com.hanlin.fadp.webapp.view.JspViewHandler的实例
* @param context
* @param controllerConfigURL
*/
public ViewFactory(ServletContext context, URL controllerConfigURL) {
// load all the view handlers
try {
Set<Map.Entry<String,String>> handlerEntries =ConfigXMLReader.getControllerConfig(controllerConfigURL).getViewHandlerMap().entrySet();
if (handlerEntries != null) {
for(Map.Entry<String,String> handlerEntry: handlerEntries) {
//将对应的handler给实例化
ViewHandlerhandler = (ViewHandler) ObjectType.getInstance(handlerEntry.getValue());
handler.setName(handlerEntry.getKey());
handler.init(context);
this.handlers.put(handlerEntry.getKey(),handler);
}
}
// load the "default" type
if (!this.handlers.containsKey("default")) {
ViewHandler defaultHandler =(ViewHandler) ObjectType.getInstance("com.hanlin.fadp.webapp.view.JspViewHandler");
defaultHandler.init(context);
this.handlers.put("default", defaultHandler);
}
} catch (Exception e) {
Debug.logError(e, module);
throw new GeneralRuntimeException(e);
}
}
在经过多contoller文件的request 和response标签处理后,其中的response中对应type=“view”会到对应的view-map标签处理,最终处理如下:
try {
if (Debug.verboseOn())Debug.logVerbose("Rendering view [" + nextPage + "] of type[" + viewMap.type + "]", module);
ViewHandlervh = viewFactory.getViewHandler(viewMap.type);
vh.render(view,nextPage, viewMap.info, contentType, charset, req, resp);
} catch (ViewHandlerException e) {
Throwable throwable = e.getNested()!= null ? e.getNested() : e;
throw newRequestHandlerException(e.getNonNestedMessage(), throwable);
}
标记的第一步是根据key获取上文初始化中的对应ViewHandler实例,这个key来自于view-map中的screen.具体操作如下
public ViewHandlergetViewHandler(String type) throws ViewHandlerException {
if (UtilValidate.isEmpty(type)) {
type = "default";
}
// get the view handler by type fromthe contextHandlers
ViewHandler handler =handlers.get(type);
if (handler == null) {
throw newViewHandlerException("No handler found for type: " + type);
}
return handler;
}
标记的第二步是进行具体的渲染,针对于不同类型有不同实现类进行处理,在这里只是展示一下它的接口
/**
* Render the page.
*
* @param name The name of the view.
* @param page The source of the view;could be a page, url, etc depending on the type of handler.
* @param info An info string attached tothis view
* @param request The HttpServletRequestobject used when requesting this page.
* @param response The HttpServletResponseobject to be used to present the page.
* @throws ViewHandlerException
*/
public void render(String name, Stringpage, String info, String contentType, String encoding, HttpServletRequestrequest, HttpServletResponse response) throws ViewHandlerException;
至此view的大致处理过程就清楚了。