freemarker在Spring中的View渲染关建过程

1.Spring已经集成了FreeMarker的相关组件,保存在org.springframework.web.servlet.view.freemarker之下,如下图所示:


2.在RequestMapping的处理后,是如何关联freemarker视图处理呢?关键在DispatcherServlet类中。

protected View resolveViewName(String viewName, Map model, Locale locale,
			HttpServletRequest request) throws Exception {
	for (ViewResolver viewResolver : this.viewResolvers) {
	  //返回FreeMarkerView对象,保存到view中。
		View view = viewResolver.resolveViewName(viewName, locale);
		if (view != null) {
			return view;
		}
	}
	return null;
}

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
	View view;
	//从requestmapping处理函数返回来后,根据viewname,即相对路径,获取FreeMarkerView对象。
	view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
	
	view.render(mv.getModelInternal(), request, response);
}



3.FreeMarkerView负责freemarker的渲染,其关键函数如下:

protected Configuration getConfiguration() {
        //该configuration对象是FreeMarkerConfigurer对象,而后续渲染所需要的资源将是从该configure中获取。 
        //该configuration是FreeMarkerView的成员。
	return this.configuration;
}

protected Template getTemplate(String name, Locale locale) throws IOException {
        //在getTimplate的过程中,configuration对象,也被传递到Template中,方便后续
        //构建Environment对象使用如template.getConfiguration();
	return (getEncoding() != null ?
			getConfiguration().getTemplate(name, locale, getEncoding()) :
			getConfiguration().getTemplate(name, locale));
}

protected Template getTemplate(Locale locale) throws IOException {
  //通过getUrl获
	return getTemplate(getUrl(), locale);
}
	
protected void doRender(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {

	SimpleHash fmModel = buildTemplateModel(model, request, response);

	Locale locale = RequestContextUtils.getLocale(request);
	processTemplate(getTemplate(locale), fmModel, response);
}


4.它是如何把每个freemarker的指令存放到configure中的呢?如下:

@Autowired(required = false)
private void TemplateComponent::setFreeMarkerConfigurer(FreeMarkerConfigurer freeMarkerConfigurer,
		Map taskDirectiveMap,
		Map templateDirectiveMap, Map methodMap)
		throws IOException, TemplateModelException {
	Map freemarkerVariables = new HashMap();
	adminConfiguration = freeMarkerConfigurer.getConfiguration();
	log.info("Freemarker directives and methods Handler started");

	//根据自定义命名规则,建立命名列表。
	StringBuffer templateDirectives = new StringBuffer();
	for (Entry entry : templateDirectiveMap.entrySet()) {
		String directiveName = directivePrefix
				+ uncapitalize(entry.getKey().replaceAll(directiveRemoveRegex, BLANK));
		freemarkerVariables.put(directiveName, entry.getValue());
		if (0 != templateDirectives.length()) {
			templateDirectives.append(COMMA_DELIMITED);
		}
		templateDirectives.append(directiveName);
	}
	StringBuffer methods = new StringBuffer();
	for (Entry entry : methodMap.entrySet()) {
		String methodName = uncapitalize(entry.getKey().replaceAll(methodRemoveRegex, BLANK));
		freemarkerVariables.put(methodName, entry.getValue());
		if (0 != methods.length()) {
			methods.append(COMMA_DELIMITED);
		}
		methods.append(methodName);
	}
	//将命名列表和bean对象一一对应地保存到configuration中。
	adminConfiguration.setAllSharedVariables(new SimpleHash(freemarkerVariables, adminConfiguration.getObjectWrapper()));
}

public void Configuration::setAllSharedVariables(TemplateHashModelEx hash) throws TemplateModelException {
    TemplateModelIterator keys = hash.keys().iterator();
    TemplateModelIterator values = hash.values().iterator();

    while(keys.hasNext()) {
        //逐个将自定义命令和对应的bean实例,以一一对应方式保存到Configure的sharedVariable成员中。
        //_memory与MemoryDirective
        this.setSharedVariable(((TemplateScalarModel)keys.next()).getAsString(), values.next());
    }
}


5.它是如何处理模板呢?

protected void FreeMarkerView::processTemplate(Template template, SimpleHash model, HttpServletResponse response)
		throws IOException, TemplateException {

	template.process(model, response.getWriter());
}

public Template::Environment(Template template, TemplateHashModel rootDataModel, Writer out) {
    super(template);
    //模板中取出configuration,configuration已经包括各种模板扩展的自定义指令。
    this.configuration = template.getConfiguration();
    this.globalNamespace = new Environment.Namespace((Template)null);
    this.currentNamespace = this.mainNamespace = new Environment.Namespace(template);
    this.out = out;
    this.rootDataModel = rootDataModel;
    //分析模板结构,构建出指令树。
    this.importMacros(template);
}

public Environment Template::createProcessingEnvironment(Object dataModel, Writer out, ObjectWrapper wrapper) throws TemplateException, IOException {    
    return new Environment(this, (TemplateHashModel)dataModelHash, out);
}

//递归式,处理每一个自定义指令。
void Environment::visit(TemplateElement element) throws IOException, TemplateException {
    this.pushElement(element);
    try {
        //element.accept就是自定义指令的执行过程,如它会调用MemoryDirective。
        TemplateElement[] te = element.accept(this);
        if(te != null) {
            TemplateElement[] var3 = te;
            int var4 = te.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                TemplateElement el = var3[var5];
                if(el == null) {
                    break;
                }

                this.visit(el);
            }
        }
    } catch (TemplateException var10) {
        this.handleTemplateException(var10);
    } finally {
        this.popElement();
    }
}
//从Root节点开始,处理自定义模板指令。
public void Environment::process() throws TemplateException, IOException {
	this.visit(this.getTemplate().getRootTreeNode());
}

public void Template::process(Object dataModel, Writer out) throws TemplateException, IOException {
    //this.createProcessingEnvironment(dataModel, out, (ObjectWrapper)null),返回的是Environment对象。
    this.createProcessingEnvironment(dataModel, out, (ObjectWrapper)null).process();
}

6.每个模块执行过程:element.accept(this))最终会调用以下代码。

@Component
public class MemoryDirective extends AbstractTemplateDirective {
    @Override
    public void execute(RenderHandler handler) throws IOException, Exception {
        Runtime runtime = Runtime.getRuntime();
        handler.put("freeMemory", runtime.freeMemory());
        handler.put("totalMemory", runtime.totalMemory());
        handler.put("maxMemory", runtime.maxMemory());
        handler.render();
    }
}