Velocity源码分析以及Spring集成

 2019-10-17 21:31  阅读(1205)
文章分类:Spring boot

### Velocity与JSP ### 从上面的JSP渲染机制我们可以看出JSP文件渲染其实和Velocity的渲染机制很不一样,JSP文件实际上执行的是JSP对应的Java类,简单地说就是将JSP的HTML转化成out.write输出,而JSP中的Java代码直接复制到翻译后的Java类中。最终执行的是翻译后的Java类,而Velocity是按照语法规则解析成一棵语法树,然后执行这棵语法树来渲染出结果。所以它们有如下这些区别。 1. 执行方式不一样:JSP是编译执行,而Velocity是解释执行。如果JSP文件被修改了,那么对应的Java类也会被重新编译,而Velocity却不需要,只是会重新生成一棵语法树。 2. 执行效率不同:从两者的执行方式不同可以看出,它们的执行效率不一样,从理论上来说,编译执行的效率明显好于解释执行,一个很明显的例子在JSP中方法调用是直接执行的,而Velocity的方法调用是反射执行的,JSP的效率会明显好于Velocity。当然如果JSP中有语法JSTL,语法标签的执行要看该标签的实现复杂度。 3. 需要的环境支持不一样:JSP的执行必须要有Servlet的运行环境,也就是需要ServletContext、HttpServletRequest和HttpServletResponse类。而要渲染Velocity完全不需要其他环境类的支持,直接给定Velocity模板就可以渲染出结果。所以Velocity不只应用在Servlet环境中。 velocity模板渲染的步骤: 1) 首先初始化启动Velocity引擎,可以通过Velocity.init()或者新建VelocityEngine类,并调用其中的init()方法; 2) 创建一个VelocityContext对象,将变量名与值关联起来,与HashMap对象相类似。可以直接将值传递给页面进行引用; 3) 获取一个模板,利用Velocity.getTemplate()获取一个渲染模板,即要将数据最终渲染在哪个页面上去。 4) 创建一个输出流,将上述创建的数据最终渲染到模板上,采用的方法template.merge() 代码示例: try \{ Velocity.init(“velocity.properties”); VelocityContext context = new VelocityContext(); String templateFile = “template.vm”; context.put(“paramObject”, “onlyone”); Template template = null; template = Velocity.getTemplate(templateFile); BufferedWriter writer = new BufferedWriter(new FileWriter(“velocity.data”)); if (template != null) template.merge(context, writer); writer.flush(); writer.close(); \} catch (Exception e) \{ e.printStackTrace(); \} 原理分析: 整体工作流程图: ![2019101710073\_1.png][2019101710073_1.png] 1. Velocity引擎初始化及启动 Velocity引擎在启动时,无论是采用Velocity.init()还是采用新建VelocityEngine的方式均会调用RuntimeInstance类中的init方法,通过设置的引擎属性初始化引擎,包括国际化支持,ResourceLoader设置,字符编码来完成一些属性资源及原始指令的加载工作。 1)initializeProperties()方法:初始化velocity的全局属性信息,即velocity.properties中配置的信息。首先会加载velocity自身所带的一个全局velocity.properties文件(org\\apache\\velocity\\runtime\\defaults\\velocity.properties),若用户自己有写velocity.properties文件,则会将其中已经加载的一些属性覆盖掉。 2)initializeLog()方法:初始化velocity的日志信息。 3)initializeResourceManager()方法:初始化velocity的资源管理。 4)initializeDirectives()方法:初始化velocity中的语法法则。 5)initializeEventHandlers()方法:初始化事件句柄。 6)initializeParserPool()方法:初始化velocity的解析工具。 7)initializeIntrospection()方法:根据所获取到的uberspect名称实例化类。 8)vmFactory.initVelocimacro()方法:实例化VM工厂,它将从运行时中获取属性值,并初始化所有的宏。 2. 查找并解析模板 通过资源加载器(ResourceLoader)将模板文件加载到内存(转化为InputStream),然后通过AST(Abstract Syntax Tree)解析器将InputStream解析为一个AST。上面的代码,当执行Velocity.getTemplate(“template.vm”)时,首先通过ResourceLoader将以字节流的形式加载template.vm文件,然后通过Parser生成如下Token集合:\{\[ Hello\], \[$foo\], \[world! \]\},可以发现velocity根本不关心模板最终要渲染出来的是html还是其他什么东西,在此处对于velocity而言html标签意味着就是纯文本标签。最终构建的AST如下: ![2019101710073\_2.png][2019101710073_2.png] 根节点下有三个子节点: \[ Hello\] 对应ASTText节点(纯文本节点) \[$foo\] 对应ASTReference节点(需要替换的引用节点) \[world! \] 对应ASTText节点 (纯文本节点) Velocity引擎在这里有个优化策略,可以针对生成的语法树进行cache 深入分析: ![2019101710073\_3.png][2019101710073_3.png] Velocity为其模板语法定义了一份jjt文件,根据这份jjt文件,使用JJTree生成一个语法解析器。 Velocity将模板解析的过程完全交给了语法解析器,调用解析器的parse方法直接得到AST,这一棵AST的每一个节点都对应一个SimpleNode的子类,其中不同的语法元素对应的不同的SimpleNode,比如\#if条件表达式对应的SimpleNode是ASTIfStatement,而\#stop指令对应的SimpleNode是ASTStop。得到了AST以后,模板的渲染就比较简单了,无非就是递归地调用各个节点的SimpleNode的render方法来完成模板的渲染过程。 在了解了模板的渲染过程后,那模板上的方法是如何在渲染过程中执行的?对于Velocity里面的引用,比如$Person这样的,最后都被解析成AST中的ASTReference节点,而对于$Person.name这样的,ASTReference下面有一个ASTIdentifier节点,$Person.saySomething()这样的,ASTReference下面有一个ASTMethod节点。不论是ASTMethod还是ASTIdentifier,最后都是通过Uberspect和Introspector这两个类来完成对方法的查找,最后调用各种Executor来实现对方法的调用。 Uberspect这个类的功能是通过反射(Reflection)和内省(Introspection)来完成对需要调用的方法的获取的,而Introspector这个类的功能是根据方法名和方法参数在一个类中查找Method对象。另外,为了提高性能,会对Method的数据进行了缓存(见IntrospectionCacheData,IntrospectorCache和IntrospectorCacheImpl三个类),以便下次快速可以找到。 找到Method以后,具体的方法的执行由各个Executor控制,每一个Executor都继承了AbstractExecutor,给外部提供统一的接口去调用。 3.上下文VelocityContext 将k–v属性对注入到上下文参数中 VelocityContext context = newVelocityContext(); context.put(“paramObject”,”onlyone”); 4. 模板渲染,输出字符 当执行template.merge(context, writer);时,模板遍历其对应的AST树,执行每个节点的渲染过程。如ASTText节点只是简单的将文本写入writer。ASTReference节点需要从context中获取引用的参数paramObject的值onlyone将$\{paramObject\}替换,并写入到writer中。Velocity的AST中有多种节点,如ASTIdentitor等,有些需要反射机制处理。当整个AST遍历结束,也就意味着模板渲染结束,渲染的结果写入writer流中。 Spring与Velocity的整合 Spring MVC是基于DispatcherServlet拦截请求并找到相应的控制器进行业务逻辑处理。Velocity与Spring整合主要需要配置的一些文件。 web.xmlcontextConfigLocation classpath:applicationContext.xmlorg.springframework.web.context.ContextLoaderListenerspringDispatcher org.springframework.web.servlet.DispatcherServletcontextConfigLocation /WEB-INF/springDispatcher-servlet.xmlspringDispatcher \*.do springDispatcher-servlet.xml中的配置信息: <–1、对模型视图名称的解析,即在模型视图名称添加前后缀 –>text/html;charset=UTF-8<–2、velocity的一些设置 –>velocity/UTF-8 UTF-8 text/html;charset=UTF-81处的工作即是定义模型视图名称的解析规则,这里我们采用的是velocity模板视图解析器,这样Spring就与velocity模板技术整合起来了。Spring的Dispatcher中有一个属性为viewResolver,通过它来寻找真正的视图对象。 2处定义了velocity的一些属性配置,包括资源的加载路径和页面的编码格式等。 ——————— 本文来自 wanghjbuf 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/wanghjbuf/article/details/52015034?utm\_source=copy [2019101710073_1.png]: https://gitee.com/chenssy/blog-home/raw/master/image/series-images/springboot/2019101710073_1.png [2019101710073_2.png]: https://gitee.com/chenssy/blog-home/raw/master/image/series-images/springboot/2019101710073_2.png [2019101710073_3.png]: https://gitee.com/chenssy/blog-home/raw/master/image/series-images/springboot/2019101710073_3.png ------- 来源:[]()

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Velocity源码分析以及Spring集成

相关推荐