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();
}
}