浅析Velocity加载机制

浅析Velocity加载机制

项目注册VelocityEngine的代码

velocity.properties

从前面两句代码可以知道作用是从velocity.properties配置文件加载Properties这个类中,并且以设置key和value的形式存储在Properties中,方便VelocityEngine这个类使用。
接下来看这个带一个参数的构造方法

我们可以看VelocityEngine类的部分源码
public class VelocityEngine implements RuntimeConstants {

      //-- 创建RuntimeInstance单实例,使用的是单例模式
      private RuntimeInstance ri = new RuntimeInstance();

      public VelocityEngine() {}

     public VelocityEngine(String propsFilename) {
        ri.setProperties(propsFilename);
     }

    public VelocityEngine(Properties p) {
        ri.setProperties(p);
    }

    public void init() {
        ri.init();
    }

    public void init(String propsFilename) {
        ri.init(propsFilename);
    }

   public void init(Properties p) {
        ri.init(p);
    }
  
    //-- 其它部分
    ......
      
}
从上面部分代码可以看出创建VelocityEngine实例的时候,也会初始化RuntimeConstants常量接口,部分代码:
package org.apache.velocity.runtime;

public interface RuntimeConstants {

     String ENCODING_DEFAULT = "ISO-8859-1";

     String DEFAULT_RUNTIME_PROPERTIES = "org/apache/velocity/runtime/defaults/velocity.properties";
  
     String DEFAULT_RUNTIME_DIRECTIVES = "org/apache/velocity/runtime/defaults/directive.properties";

      int NUMBER_OF_PARSERS = 20;

}
整个常量接口就是定义默认配置文件中key值以及一些key的默认value值。
接下里也会创建一个RuntimeInstance实例,再来看整个RuntimeInstance类部分源码,至于他的父类接口都是会加载的,不再看具体父接口的代码,
package org.apache.velocity.runtime;

public class RuntimeInstance implements RuntimeConstants, RuntimeServices {
   
     private  VelocimacroFactory vmFactory = null;

     private Log log = new Log();

     private  ParserPool parserPool;

    private boolean initializing = false;

    private volatile boolean initialized = false;

    private  ExtendedProperties overridingProperties = null;

    .....

    private Introspector introspector = null;

    private Map applicationAttributes = null;

    private String encoding;
    
   //-- 构造方法
   public RuntimeInstance() {
    
        vmFactory = new VelocimacroFactory( this );

        introspector = new Introspector(getLog());

        applicationAttributes = new HashMap();

    }

   public Log getLog() {
        return log;
    }
 
}

这个类RuntimeInstance的实例创建完毕之后,在VelocityEngine中将新设置的属性通过RuntimeInstance的setProperties()方法设置到RuntimeInstance实例对象中存储。
以上仅仅只是设置属性内容,那么Velocity到底是怎么进行初始化的呢?
如果在Spring容器启动的时候不初始化Velocity,那么就需要自己在项目中自己写代码进行初始化
截取一段代码
String vm = "/template/debt-listing-apply.html";
VelocityContext context = new VelocityContext();
context.put("project", project);
StringWriter stringWriter = new StringWriter();
velocityEngine.mergeTemplate(vm, "UTF-8", context, stringWriter);
比较核心的两个类是VelocityContext和velocityEngine
VelocityContext部分源码:

package org.apache.velocity;

public class VelocityContext extends AbstractContext implements Cloneable {

     private static final long serialVersionUID = 9033846851064645037L;

     private Map context = null;

     public VelocityContext() {
        this(null, null);
    }

    public VelocityContext(Map context, Context innerContext) {
        super(innerContext);
        this.context = (context == null ? new HashMap() : context);
    }

}
velocityEngine部分源码:
package org.apache.velocity.app;

public class VelocityEngine implements RuntimeConstants {

    private RuntimeInstance ri = new RuntimeInstance();

    public boolean mergeTemplate(String templateName, String encoding,
                                      Context context, Writer writer )
        throws ResourceNotFoundException, ParseErrorException, MethodInvocationException {
        Template template = ri.getTemplate(templateName, encoding);

        if ( template == null )
        {
            String msg = "VelocityEngine.mergeTemplate() was unable to load template '"
                           + templateName + "'";
            getLog().error(msg);
            throw new ResourceNotFoundException(msg);
        }
        else
        {
            template.merge(context, writer);
            return true;
         }
    }

}

RuntimeInstance部分源码:

package org.apache.velocity.runtime;

public class RuntimeInstance implements RuntimeConstants, RuntimeServices {

     public Template getTemplate(String name, String  encoding)
        throws ResourceNotFoundException, ParseErrorException {
        requireInitialization();

        return (Template)
                resourceManager.getResource(name,
                    ResourceManager.RESOURCE_TEMPLATE, encoding);
    }

    private void requireInitialization() {
        if (!initialized) {
            try {
                init();
            }
            catch (Exception e) {
                getLog().error("Could not auto-initialize Velocity", e);
                throw new RuntimeException("Velocity could not be initialized!", e);
            }
        }
    }

   public synchronized void init() {
        if (!initialized && !initializing) {
            log.debug("Initializing Velocity, Calling init()...");
            initializing = true;

            log.trace("*******************************************************************");
            log.debug("Starting Apache Velocity v1.7 (compiled: 2010-11-19 12:14:37)");
            log.trace("RuntimeInstance initializing.");

            initializeProperties();
            initializeLog();
            initializeResourceManager();
            initializeDirectives();
            initializeEventHandlers();
            initializeParserPool();

            initializeIntrospection();
            initializeEvaluateScopeSettings();
            /*
             *  initialize the VM Factory.  It will use the properties
             * accessable from Runtime, so keep this here at the end.
             */
            vmFactory.initVelocimacro();

            log.trace("RuntimeInstance successfully initialized.");

            initialized = true;
            initializing = false;
        }
    }

   private void initializeProperties() {
        if (configuration.isInitialized() == false) {
            setDefaultProperties();
        }

        if( overridingProperties != null) {
            configuration.combine(overridingProperties);
        }
    }

   ......

}
通过跟踪源码,知道了自己设置的属性是在什么时候加载和设置到Velocity中,又是怎么加载默认配置文件的,又是怎么进行一步一步初始化的。详细了解可以看源码。
上述的方式仅仅是在方法的调用时进行初始化,如果是在Spring容器启动的过程中进行初始化,那么就需要加载VelocityServlet和初始化,不过Spring4.3之后不再支持,需要做一些特殊的处理,在Spring初始化时也加载这个Servlet,并且初始化这个Servlet,
下面会调用:


接下来调用

接着调用

最终还是使用RuntimeInstance的init()方法进行初始化。如果需要使用Velocity模板进行页面开发,那么就需要在Spring容器加载初始化时做特殊处理。

附上默认配置文件内容
默认velocity.properties配置文件内容
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.    

# ----------------------------------------------------------------------------
# R U N T I M E  L O G
# ----------------------------------------------------------------------------

# ----------------------------------------------------------------------------
#  default LogChute to use: default: AvalonLogChute, Log4JLogChute, CommonsLogLogChute, ServletLogChute, JdkLogChute
# ----------------------------------------------------------------------------

runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogChute,org.apache.velocity.runtime.log.Log4JLogChute,org.apache.velocity.runtime.log.CommonsLogLogChute,org.apache.velocity.runtime.log.ServletLogChute,org.apache.velocity.runtime.log.JdkLogChute

# ---------------------------------------------------------------------------
# This is the location of the Velocity Runtime log.
# ----------------------------------------------------------------------------

runtime.log = velocity.log

# ----------------------------------------------------------------------------
# This controls whether invalid references are logged.
# ----------------------------------------------------------------------------

runtime.log.invalid.references = true

# ----------------------------------------------------------------------------
# T E M P L A T E  E N C O D I N G
# ----------------------------------------------------------------------------

input.encoding=ISO-8859-1
output.encoding=ISO-8859-1

# ----------------------------------------------------------------------------
# F O R E A C H  P R O P E R T I E S
# ----------------------------------------------------------------------------
# These properties control how the counter is accessed in the #foreach
# directive. By default the reference $velocityCount and $velocityHasNext
# will be available in the body of the #foreach directive.
# The default starting value for $velocityCount is 1.
# ----------------------------------------------------------------------------

directive.foreach.counter.name = velocityCount
directive.foreach.counter.initial.value = 1
directive.foreach.maxloops = -1

directive.foreach.iterator.name = velocityHasNext

# ----------------------------------------------------------------------------
# S E T  P R O P E R T I E S
# ----------------------------------------------------------------------------
# These properties control the behavior of #set.
# For compatibility, the default behavior is to disallow setting a reference
# to null.  This default may be changed in a future version.
# ----------------------------------------------------------------------------

directive.set.null.allowed = false

# ----------------------------------------------------------------------------
# I F  P R O P E R T I E S
# ----------------------------------------------------------------------------
# These properties control the behavior of #if
# Default behavior is to check return value of toString() and treat an object
# with toString() that returns null as null. If all objects have toString()
# methods that never return null, this check is unnecessary and can be disabled
# to gain performance. In Velocity 1.5, no such null check was performed.
directive.if.tostring.nullcheck = true

# ----------------------------------------------------------------------------
# I N C L U D E  P R O P E R T I E S
# ----------------------------------------------------------------------------
# These are the properties that governed the way #include'd content
# is governed.
# ----------------------------------------------------------------------------

directive.include.output.errormsg.start = <!-- include error :
directive.include.output.errormsg.end   =  see error log -->

# ----------------------------------------------------------------------------
# P A R S E  P R O P E R T I E S
# ----------------------------------------------------------------------------

directive.parse.max.depth = 10

# ----------------------------------------------------------------------------
# S C O P E  P R O P E R T I E S
# ----------------------------------------------------------------------------
# These are the properties that govern whether or not a Scope object
# is automatically provided for each of the given scopes to serve as a
# scope-safe reference namespace and "label" for #break calls. The default
# for most of these is false.  Note that <bodymacroname> should be replaced by
# name of macros that take bodies for which you want to suppress the scope.
# ----------------------------------------------------------------------------
# template.provide.scope.control = false
# evaluate.provide.scope.control = false
foreach.provide.scope.control = true
# macro.provide.scope.control = false
# define.provide.scope.control = false
# <bodymacroname>.provide.scope.control = false

# ----------------------------------------------------------------------------
# T E M P L A T E  L O A D E R S
# ----------------------------------------------------------------------------
#
#
# ----------------------------------------------------------------------------

resource.loader = file

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 2

string.resource.loader.description = Velocity String Resource Loader
string.resource.loader.class = org.apache.velocity.runtime.resource.loader.StringResourceLoader

# ----------------------------------------------------------------------------
# VELOCIMACRO PROPERTIES
# ----------------------------------------------------------------------------
# global : name of default global library.  It is expected to be in the regular
# template path.  You may remove it (either the file or this property) if
# you wish with no harm.
# ----------------------------------------------------------------------------
# velocimacro.library = VM_global_library.vm

velocimacro.permissions.allow.inline = true
velocimacro.permissions.allow.inline.to.replace.global = false
velocimacro.permissions.allow.inline.local.scope = false

velocimacro.context.localscope = false
velocimacro.max.depth = 20

# ----------------------------------------------------------------------------
# VELOCIMACRO STRICT MODE
# ----------------------------------------------------------------------------
# if true, will throw an exception for incorrect number 
# of arguments.  false by default (for backwards compatibility)
# but this option will eventually be removed and will always
# act as if true
# ----------------------------------------------------------------------------
velocimacro.arguments.strict = false

# ----------------------------------------------------------------------------
# VELOCIMACRO BODY REFERENCE 
# ----------------------------------------------------------------------------
# Defines name of the reference that can be used to render the AST block passed to
# block macro call as an argument inside a macro.
# ----------------------------------------------------------------------------
velocimacro.body.reference=bodyContent

# ----------------------------------------------------------------------------
# STRICT REFERENCE MODE
# ----------------------------------------------------------------------------
# if true, will throw a MethodInvocationException for references
# that are not defined in the context, or have not been defined
# with a #set directive. This setting will also throw an exception
# if an attempt is made to call a non-existing property on an object
# or if the object is null.  When this property is true then property
# 'directive.set.null.allowed' is also set to true.
# ----------------------------------------------------------------------------
runtime.references.strict = false

# ----------------------------------------------------------------------------
# INTERPOLATION
# ----------------------------------------------------------------------------
# turn off and on interpolation of references and directives in string
# literals.  ON by default :)
# ----------------------------------------------------------------------------
runtime.interpolate.string.literals = true


# ----------------------------------------------------------------------------
# RESOURCE MANAGEMENT
# ----------------------------------------------------------------------------
# Allows alternative ResourceManager and ResourceCache implementations
# to be plugged in.
# ----------------------------------------------------------------------------
resource.manager.class = org.apache.velocity.runtime.resource.ResourceManagerImpl
resource.manager.cache.class = org.apache.velocity.runtime.resource.ResourceCacheImpl

# ----------------------------------------------------------------------------
# PARSER POOL
# ----------------------------------------------------------------------------
# Selects a custom factory class for the parser pool.  Must implement
# ParserPool.  parser.pool.size is used by the default implementation
# ParserPoolImpl
# ----------------------------------------------------------------------------

parser.pool.class = org.apache.velocity.runtime.ParserPoolImpl
parser.pool.size = 20


# ----------------------------------------------------------------------------
# EVENT HANDLER
# ----------------------------------------------------------------------------
# Allows alternative event handlers to be plugged in.  Note that each
# class property is actually a comma-separated list of classes (which will
# be called in order).
# ----------------------------------------------------------------------------
# eventhandler.referenceinsertion.class =
# eventhandler.nullset.class =
# eventhandler.methodexception.class =
# eventhandler.include.class =


# ----------------------------------------------------------------------------
# EVALUATE
# ----------------------------------------------------------------------------
# Evaluate VTL dynamically in template.  Select a class for the Context, if
# you want all #set calls within it to be locally scoped.  This feature is
# deprecated; please use $evaluate to hold local references instead.
# ----------------------------------------------------------------------------

#directive.evaluate.context.class = org.apache.velocity.VelocityContext


# ----------------------------------------------------------------------------
# PLUGGABLE INTROSPECTOR
# ----------------------------------------------------------------------------
# Allows alternative introspection and all that can of worms brings.
# ----------------------------------------------------------------------------

runtime.introspector.uberspect = org.apache.velocity.util.introspection.UberspectImpl


# ----------------------------------------------------------------------------
# SECURE INTROSPECTOR
# ----------------------------------------------------------------------------
# If selected, prohibits methods in certain classes and packages from being 
# accessed.
# ----------------------------------------------------------------------------

introspector.restrict.packages = java.lang.reflect

# The two most dangerous classes

introspector.restrict.classes = java.lang.Class
introspector.restrict.classes = java.lang.ClassLoader
                
# Restrict these for extra safety

introspector.restrict.classes = java.lang.Compiler
introspector.restrict.classes = java.lang.InheritableThreadLocal
introspector.restrict.classes = java.lang.Package
introspector.restrict.classes = java.lang.Process
introspector.restrict.classes = java.lang.Runtime
introspector.restrict.classes = java.lang.RuntimePermission
introspector.restrict.classes = java.lang.SecurityManager
introspector.restrict.classes = java.lang.System
introspector.restrict.classes = java.lang.Thread
introspector.restrict.classes = java.lang.ThreadGroup
introspector.restrict.classes = java.lang.ThreadLocal
directive.properties默认配置文件内容
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.    
directive.1=org.apache.velocity.runtime.directive.Foreach
directive.2=org.apache.velocity.runtime.directive.Include
directive.3=org.apache.velocity.runtime.directive.Parse
directive.4=org.apache.velocity.runtime.directive.Macro
directive.5=org.apache.velocity.runtime.directive.Literal
directive.6=org.apache.velocity.runtime.directive.Evaluate
directive.7=org.apache.velocity.runtime.directive.Break
directive.8=org.apache.velocity.runtime.directive.Define
directive.9=org.apache.velocity.runtime.directive.Stop


猜你喜欢

转载自blog.csdn.net/erlian1992/article/details/80794679