velocity就是由template,engine,context組成。
1、首先創建一個template(如果是用在web上就是一個html文件),將需要參數化或實例化的地方用跟context有關的符號標記出來,標記時用velocity template language。而template應該可以是任意的文本。
2、給context設定一些值,這些值用來替換在template中被標記的地方。
3、利用engine將template中需要替換的地方用context中的值替換掉,也就是所謂的merge,從而得到該模板的實例。
Velocity的初始化有多種方式:
1、init()
2、init(Properties p)
3、init(String propertiesName)
第一種init()方式是最簡單的方式,當我們的程序沒有配置類似velocity.properties這樣的文件的時候,就會使用默認的配置文件來初始化,
默認的配置文件的位置在org/apache/velocity/runtime/defaults/velocity.properties
應用在WEB的時候,默認的配置文件使用的是org/apache/velocity/tools/view/servlet/velocity.properties
在初始化前,velocity會把配置文件的屬性和值讀取后保存在內存中,初始化時,velocity將會初始化以下幾個方面:
- Logging System 日志系統
- ResourceManager 資源加載器
- EventHandler 事件句柄
- Parser Pool 解析池
- Global Cache 全局緩存
- Velocimacro System 宏
Logging System
velocity會根據配置文件里的信息,查找一個名叫runtime.log.logsystem的屬性,一旦配置文件中有配置這個屬性,則會開始去創建日志系統。當velocity沒有配置runtime.log.logsystem這個屬性的時候,則會繼續尋找runtime.log.logsystem.class這個屬性,默認的velocity.properties配置文件中,這個屬性的值按順序依次為
- AvalonLogChute
- Log4JLogChute
- CommonsLogLogChute
- ServletLogChute
- JdkLogChute
當然,velocity不會使用那么多個日志系統,只會使用第一個能實例化的日志系統。如果之前的創建工作都失敗的話,那么意味着用戶沒有設置值或者是沒有找到類,velocity將會使用系統統默認的SystemLogChute來輸出日志,這個日志系統使用System.err方式輸出日志。一旦使用runtime.log.logsystem或者runtime.log.logsystem.class屬性創建日志系統成功后,velocity就會把HoldingLogChute替換成新的日志系統。這樣,日志的初始化才真正的結束。
ResourceManager
資源加載器是velocity加載資源使用的一個工具。Velocity的配置文件里有個屬性叫Resource.manager.class,默認的class是org.apache.velocity.runtime.resource.ResourceManagerImpl。Velocity會嘗試初始化ResourceManagerImpl,其中會查找resource.loader這個屬性,resource.loader這個屬性是可以有多個的,每個Loader都會生效。
ResourceLoader一共有7種:
- ClasspathResourceLoader
- DataSourceResourceLoader
- FileResourceLoader
- JarResourceLoader
- StringResourceLoader
- URLResourceLoader
- WebappLoader
默認的是第3個FileResourceLoader。除了第7個webappLoader是velocity-tools包作為velocity的附屬工具后來添加的,其余6個都velocity包自帶的,如果覺得這些都不適用,你也可以自己實現一個。實現一個資源加載器只要繼承ResourceLoader,實現它的幾個方法就可以了。所謂的資源加載器指的就是velocity讀取文件的方法,有直接從文件讀取的,有從jar包中讀取的,也有從類路徑中讀取的,基本上只要自己重寫getResourceStream方法就可以。在初始化的過程中,會讀取resource.manager.logwhenfound和resource.manager.cache.class這兩個屬性,同時,也會進行資源緩存的初始化操作。
EventHandler
用戶可以自定義響應的事件,Velocity提供了對模板解析過程事件的處理,用戶可以響應模板產生的事件。
org.apache.velocity.app.event.EventHandler,是一個最簡單的接口。我們可以通過實現這個接口來處理頁面上不同的信息。
1)、IncludeEventHandler
在使用#include(),#parse()語法的時候,允許開發修改include或者parse文件的路徑(一般用於資源找不到的情況)。
IncludeEventHandler有兩個實現類,分別是IncludeNotFound和IncludeRelativePath。
當找不到#include指令的文件時,IncludeNotFound類會去做一些處理,例如去增加一個eventhandler.include.notfound=notfound.vm的配置,當然,如果不存在notfound.vm,也會給出"Can't find include not found page"的提示。
2)、InvalidReferenceEventHandler
當渲染頁面的時候,一旦遇到非法的reference,就會觸發此事件。開發者可以偵聽此事件,用於錯誤的報告,或者修改返回的內容。
ReportInvalidReferences是它的一個實現類,用於報告無效的refenrences。如果在velocity的配置文件中使用了eventhandler.invalidreference.exception=true配置,在運行過程中碰到第一個無效的refenrences就會拋出ParseErrorRuntimeException異常,執行暫停。如果配置為false的話,則會將錯誤先收在InvalidReferenceInfo列表對象中,運行照舊。
3)、MethodExceptionEventHandler
渲染模板,一旦發現調用的方法拋出異常的時候,就會觸發此事件。允許開發者處理這個異常,輸出友好信息或者拋出異常。必須返回一個值用於模板的渲染。
4)、NullSetEventHandler
當使用#set()語法,設置一個null值的時候,會觸發此事件。目前Velocity官方沒有提供默認實現。
5)、ReferenceInsertionEventHandler
當渲染變量(reference)的時候,就會觸發此事件。允許開發者返回更加友好的值--一般用於內容的escape,比如HtmlEscape等。
Parser Pool
Velocity會使用類似線程池的機制來解析頁面。配置的key為parser.pool.class和parser.pool.size。默認的實現類為org.apache.velocity.util.SimplePoolVelocity。
velocity啟動時需要創建模板解析器的個數. 默認為20個,對一般用戶來說足夠了. 即使這個值小了,Velocity也會運行時根據系統需要動態增加(但增加的不會裝入解析池中). 新增時會在日志中輸出信息。
Global Cache 全局緩存
開啟全局緩存配置項 file.resource.loader.cache=true file.resource.loader.modificationCheckInterval=-1
Template t = getTemplate(stack, velocityManager.getVelocityEngine(), invocation, finalLocation, encoding); VelocityResult.java : protected Template getTemplate(ValueStack stack, VelocityEngine velocity, ActionInvocation invocation, String location, String encoding) throws Exception { if (!location.startsWith("/")) { location = invocation.getProxy().getNamespace() + "/" + location; } Template template = velocity.getTemplate(location, encoding); return template; } VelocityEngine.java public Template getTemplate(String name, String encoding) throws ResourceNotFoundException, ParseErrorException, Exception { return ri.getTemplate( name, encoding ); } RuntimeInstance.java public Template getTemplate(String name, String encoding) throws ResourceNotFoundException, ParseErrorException, Exception { requireInitialization(); return (Template) resourceManager.getResource(name, ResourceManager.RESOURCE_TEMPLATE, encoding); } ResourceManagerImpl.java public Resource getResource(final String resourceName, final int resourceType, final String encoding) throws ResourceNotFoundException, ParseErrorException, Exception { String resourceKey = resourceType + resourceName; Resource resource = globalCache.get(resourceKey); ResourceCacheImpl.java public Resource get( Object key ) { return (Resource) cache.get( key ); }
Velocimacro(宏配置)
當Velocity engine運行時,會載入一個全局的宏文件。所有模板都可訪問該宏文件(Velocimacros). 這個文件位置在相對於資源文件的根目錄下。velocity默認的配置項為velocimacro.library=VM_global_library.vm。此外,還有一些其他配置來處理宏的不同使用情況,例如:
velocimacro.permissions.allow.inline=true定義在模板中是否可用#macro()指令定義一個新的宏。默認為true,表示所有的vm都可以新建宏,但是要注意可能會把全局的宏配置給替換掉。
velocimacro.permissions.allow.inline.to.replace.global=false控制用戶定義的宏是否可以可以替換Velocity的全局宏。
velocimacro.library.autoreload=false控制宏是否自動載入。當值為true時宏將根據是否修改而決定是否需要重新加載,這個特性可在調試時很方便,不需重啟你的服務器。
