Browse Source

添加 removeSharedMethod(Class<?> sharedClass)方法,支持移除整个 class 中的 Shared Method

James 3 years ago
parent
commit
db7b246e87

+ 119 - 111
src/main/java/com/jfinal/template/Engine.java

@@ -42,60 +42,60 @@ import com.jfinal.template.stat.ast.Stat;
 
 /**
  * Engine
- * 
+ *
  * Example:
  * Engine.use().getTemplate(fileName).render(...);
  * Engine.use().getTemplate(fileName).renderToString(...);
  */
 public class Engine {
-	
+
 	public static final String MAIN_ENGINE_NAME = "main";
-	
+
 	private static Engine MAIN_ENGINE;
 	private static Map<String, Engine> engineMap = new HashMap<String, Engine>(64, 0.5F);
-	
+
 	// Create main engine
 	static {
 		MAIN_ENGINE = new Engine(MAIN_ENGINE_NAME);
 		engineMap.put(MAIN_ENGINE_NAME, MAIN_ENGINE);
 	}
-	
+
 	private String name;
 	private boolean devMode = false;
 	private boolean cacheStringTemplate = false;
 	private EngineConfig config = new EngineConfig();
 	private ISourceFactory sourceFactory = config.getSourceFactory();
-	
+
 	private Map<String, Template> templateCache = new SyncWriteMap<String, Template>(2048, 0.5F);
-	
+
 	/**
-	 * Create engine without management of JFinal 
+	 * Create engine without management of JFinal
 	 */
 	public Engine() {
 		this.name = "NO_NAME";
 	}
-	
+
 	/**
-	 * Create engine by engineName without management of JFinal 
+	 * Create engine by engineName without management of JFinal
 	 */
 	public Engine(String engineName) {
 		this.name = engineName;
 	}
-	
+
 	/**
 	 * Using the main Engine
 	 */
 	public static Engine use() {
 		return MAIN_ENGINE;
 	}
-	
+
 	/**
 	 * Using the engine with engine name
 	 */
 	public static Engine use(String engineName) {
 		return engineMap.get(engineName);
 	}
-	
+
 	/**
 	 * Create engine with engine name managed by JFinal
 	 */
@@ -111,7 +111,7 @@ public class Engine {
 		engineMap.put(engineName, newEngine);
 		return newEngine;
 	}
-	
+
 	/**
 	 * Create engine if absent with engine name managed by JFinal
 	 * <pre>
@@ -120,7 +120,7 @@ public class Engine {
 	 * 		e.setDevMode(true);
 	 * 		e.setToClassPathSourceFactory();
 	 * 	});
-	 * 
+	 *
 	 * 	engine.getTemplate("template.html").render(System.out);
 	 * </>
 	 */
@@ -137,7 +137,7 @@ public class Engine {
 		}
 		return ret;
 	}
-	
+
 	/**
 	 * Create engine with engine name managed by JFinal
 	 * <pre>
@@ -146,7 +146,7 @@ public class Engine {
 	 * 		e.setDevMode(true);
 	 * 		e.setToClassPathSourceFactory();
 	 * 	});
-	 * 
+	 *
 	 * 	engine.getTemplate("template.html").render(System.out);
 	 * </>
 	 */
@@ -155,7 +155,7 @@ public class Engine {
 		e.accept(ret);
 		return ret;
 	}
-	
+
 	/**
 	 * Remove engine with engine name managed by JFinal
 	 */
@@ -166,7 +166,7 @@ public class Engine {
 		}
 		return removed;
 	}
-	
+
 	/**
 	 * Set main engine
 	 */
@@ -178,7 +178,7 @@ public class Engine {
 		engineMap.put(Engine.MAIN_ENGINE_NAME, engine);
 		Engine.MAIN_ENGINE = engine;
 	}
-	
+
 	/**
 	 * Get template by file name
 	 */
@@ -189,7 +189,7 @@ public class Engine {
 			arr[0] = '/';
 			fileName = new String(arr);
 		}
-		
+
 		Template template = templateCache.get(fileName);
 		if (template == null) {
 			template = buildTemplateBySourceFactory(fileName);
@@ -202,7 +202,7 @@ public class Engine {
 		}
 		return template;
 	}
-	
+
 	private Template buildTemplateBySourceFactory(String fileName) {
 		// FileSource fileSource = new FileSource(config.getBaseTemplatePath(), fileName, config.getEncoding());
 		ISource source = sourceFactory.getSource(config.getBaseTemplatePath(), fileName, config.getEncoding());
@@ -215,25 +215,25 @@ public class Engine {
 		Template template = new Template(env, stat);
 		return template;
 	}
-	
+
 	/**
 	 * Get template by string content and do not cache the template
 	 */
 	public Template getTemplateByString(String content) {
 		return getTemplateByString(content, cacheStringTemplate);
 	}
-	
+
 	/**
 	 * Get template by string content
-	 * 
+	 *
 	 * 重要:StringSource 中的 cacheKey = HashKit.md5(content),也即 cacheKey
 	 *     与 content 有紧密的对应关系,当 content 发生变化时 cacheKey 值也相应变化
 	 *     因此,原先 cacheKey 所对应的 Template 缓存对象已无法被获取,当 getTemplateByString(String)
 	 *     的 String 参数的数量不确定时会引发内存泄漏
-	 *     
+	 *
 	 *     当 getTemplateByString(String, boolean) 中的 String 参数的
-	 *     数量可控并且确定时,才可对其使用缓存 
-	 *     
+	 *     数量可控并且确定时,才可对其使用缓存
+	 *
 	 * @param content 模板内容
 	 * @param cache true 则缓存 Template,否则不缓存
 	 */
@@ -241,7 +241,7 @@ public class Engine {
 		if (!cache) {
 			return buildTemplateBySource(new StringSource(content, cache));
 		}
-		
+
 		String cacheKey = HashKit.md5(content);
 		Template template = templateCache.get(cacheKey);
 		if (template == null) {
@@ -255,12 +255,12 @@ public class Engine {
 		}
 		return template;
 	}
-	
+
 	public Template getTemplateByString(String content, String cacheKey) {
 		if (cacheKey == null) {
 			return buildTemplateBySource(new StringSource(content, cacheKey));
 		}
-		
+
 		Template template = templateCache.get(cacheKey);
 		if (template == null) {
 			template = buildTemplateBySource(new StringSource(content, cacheKey));
@@ -273,7 +273,7 @@ public class Engine {
 		}
 		return template;
 	}
-	
+
 	/**
 	 * Get template by implementation of ISource
 	 */
@@ -282,7 +282,7 @@ public class Engine {
 		if (cacheKey == null) {	// cacheKey 为 null 则不缓存,详见 ISource.getCacheKey() 注释
 			return buildTemplateBySource(source);
 		}
-		
+
 		Template template = templateCache.get(cacheKey);
 		if (template == null) {
 			template = buildTemplateBySource(source);
@@ -295,7 +295,7 @@ public class Engine {
 		}
 		return template;
 	}
-	
+
 	private Template buildTemplateBySource(ISource source) {
 		Env env = new Env(config);
 		Parser parser = new Parser(env, source.getContent(), null);
@@ -306,7 +306,7 @@ public class Engine {
 		Template template = new Template(env, stat);
 		return template;
 	}
-	
+
 	/**
 	 * Add shared function by file
 	 */
@@ -314,7 +314,7 @@ public class Engine {
 		config.addSharedFunction(fileName);
 		return this;
 	}
-	
+
 	/**
 	 * Add shared function by ISource
 	 */
@@ -322,7 +322,7 @@ public class Engine {
 		config.addSharedFunction(source);
 		return this;
 	}
-	
+
 	/**
 	 * Add shared function by files
 	 */
@@ -330,7 +330,7 @@ public class Engine {
 		config.addSharedFunction(fileNames);
 		return this;
 	}
-	
+
 	/**
 	 * Add shared function by string content
 	 */
@@ -338,7 +338,7 @@ public class Engine {
 		config.addSharedFunctionByString(content);
 		return this;
 	}
-	
+
 	/**
 	 * Add shared object
 	 */
@@ -346,41 +346,41 @@ public class Engine {
 		config.addSharedObject(name, object);
 		return this;
 	}
-	
+
 	public Engine removeSharedObject(String name) {
 		config.removeSharedObject(name);
 		return this;
 	}
-	
+
 	/**
 	 * 添加枚举类型,便于在模板中使用
-	 * 
+	 *
 	 * <pre>
 	 * 例子:
 	 * 1:定义枚举类型
 	 * public enum UserType {
-	 * 
+	 *
 	 *   ADMIN,
 	 *   USER;
-	 *   
+	 *
 	 *   public String hello() {
 	 *      return "hello";
 	 *   }
 	 * }
-	 * 
+	 *
 	 * 2:配置
 	 * engine.addEnum(UserType.class);
-	 * 
+	 *
 	 * 3:模板中使用
 	 * ### 以下的对象 u 通过 Controller 中的 setAttr("u", UserType.ADMIN) 传递
 	 * #if( u == UserType.ADMIN )
 	 *    #(UserType.ADMIN)
-	 *    
+	 *
 	 *    #(UserType.ADMIN.name())
-	 *    
+	 *
 	 *    #(UserType.ADMIN.hello())
 	 * #end
-	 * 
+	 *
 	 * </pre>
 	 */
 	public Engine addEnum(Class<? extends Enum<?>> enumClass) {
@@ -391,7 +391,7 @@ public class Engine {
 		}
 		return addSharedObject(enumClass.getSimpleName(), map);
 	}
-	
+
 	/**
 	 * Set output directive factory
 	 */
@@ -399,17 +399,17 @@ public class Engine {
 		config.setOutputDirectiveFactory(outputDirectiveFactory);
 		return this;
 	}
-	
+
 	/**
 	 * 添加自定义指令
-	 * 
+	 *
 	 * 建议添加自定义指令时明确指定 keepLineBlank 变量值,其规则如下:
 	 *   1:keepLineBlank 为 true 时, 该指令所在行的前后空白字符以及末尾字符 '\n' 将会被保留
 	 *      一般用于具有输出值的指令,例如 #date、#para 等指令
-	 *    
+	 *
 	 *   2:keepLineBlank 为 false 时,该指令所在行的前后空白字符以及末尾字符 '\n' 将会被删除
 	 *      一般用于没有输出值的指令,例如 #for、#if、#else、#end 这种性质的指令
-	 * 
+	 *
 	 * <pre>
 	 * 	示例:
 	 * 	addDirective("now", NowDirective.class, true)
@@ -419,7 +419,7 @@ public class Engine {
 		config.addDirective(directiveName, directiveClass, keepLineBlank);
 		return this;
 	}
-	
+
 	/**
 	 * 添加自定义指令,keepLineBlank 使用默认值
 	 */
@@ -427,7 +427,7 @@ public class Engine {
 		config.addDirective(directiveName, directiveClass);
 		return this;
 	}
-	
+
 	/**
 	 * Remove directive
 	 */
@@ -435,7 +435,7 @@ public class Engine {
 		config.removeDirective(directiveName);
 		return this;
 	}
-	
+
 	/**
 	 * Add shared method from object
 	 */
@@ -443,7 +443,7 @@ public class Engine {
 		config.addSharedMethod(sharedMethodFromObject);
 		return this;
 	}
-	
+
 	/**
 	 * Add shared method from class
 	 */
@@ -451,7 +451,7 @@ public class Engine {
 		config.addSharedMethod(sharedMethodFromClass);
 		return this;
 	}
-	
+
 	/**
 	 * Add shared static method of Class
 	 */
@@ -459,7 +459,7 @@ public class Engine {
 		config.addSharedStaticMethod(sharedStaticMethodFromClass);
 		return this;
 	}
-	
+
 	/**
 	 * Remove shared Method by method name
 	 */
@@ -467,7 +467,7 @@ public class Engine {
 		config.removeSharedMethod(methodName);
 		return this;
 	}
-	
+
 	/**
 	 * Remove shared Method of the Class
 	 */
@@ -475,7 +475,7 @@ public class Engine {
 		config.removeSharedMethod(clazz);
 		return this;
 	}
-	
+
 	/**
 	 * Remove shared Method
 	 */
@@ -483,39 +483,47 @@ public class Engine {
 		config.removeSharedMethod(method);
 		return this;
 	}
-	
+
+	/**
+	 * Remove shared Method
+	 */
+	public Engine removeSharedMethod(String methodName, Class<?>... paraTypes) {
+		config.removeSharedMethod(methodName, paraTypes);
+		return this;
+	}
+
 	/**
 	 * Remove template cache by cache key
 	 */
 	public void removeTemplateCache(String cacheKey) {
 		templateCache.remove(cacheKey);
 	}
-	
+
 	/**
 	 * Remove all template cache
 	 */
 	public void removeAllTemplateCache() {
 		templateCache.clear();
 	}
-	
+
 	public int getTemplateCacheSize() {
 		return templateCache.size();
 	}
-	
+
 	public String getName() {
 		return name;
 	}
-	
+
 	public String toString() {
 		return "Template Engine: " + name;
 	}
-	
+
 	// Engine config below ---------
-	
+
 	public EngineConfig  getEngineConfig() {
 		return config;
 	}
-	
+
 	/**
 	 * 设置 true 为开发模式,支持模板文件热加载
 	 * 设置 false 为生产模式,不支持模板文件热加载,以达到更高的性能
@@ -528,11 +536,11 @@ public class Engine {
 		}
 		return this;
 	}
-	
+
 	public boolean getDevMode() {
 		return devMode;
 	}
-	
+
 	/**
 	 * 配置是否缓存字符串模板,也即是否缓存通过 getTemplateByString(String content)
 	 * 方法获取的模板,默认配置为 false
@@ -541,19 +549,19 @@ public class Engine {
 		this.cacheStringTemplate = cacheStringTemplate;
 		return this;
 	}
-	
+
 	/**
 	 * 设置 ISourceFactory 用于为 engine 切换不同的 ISource 实现类
 	 * ISource 用于从不同的来源加载模板内容
-	 * 
+	 *
 	 * <pre>
 	 * 配置为 ClassPathSourceFactory 时特别注意:
 	 *    由于 JFinal 会在 configEngine(Engine me) 方法调用 “之前”,会默认调用一次如下方法:
 	 *       me.setBaseTemplatePath(PathKit.getWebRootPath())
-	 *    
+	 *
 	 *    而 ClassPathSourceFactory 在以上默认值下不能工作,所以需要通过如下方式清掉该值:
 	 *       me.setBaseTemplatePath(null)
-	 *    
+	 *
 	 *    或者配置具体要用的 baseTemplatePath 值,例如:
 	 *       me.setBaseTemplatePath("view");
 	 * </pre>
@@ -563,45 +571,45 @@ public class Engine {
 		this.sourceFactory = sourceFactory;
 		return this;
 	}
-	
+
 	/**
 	 * 设置为 ClassPathSourceFactory 的快捷方法
 	 */
 	public Engine setToClassPathSourceFactory() {
 		return setSourceFactory(new ClassPathSourceFactory());
 	}
-	
+
 	public ISourceFactory getSourceFactory() {
 		return sourceFactory;
 	}
-	
+
 	public Engine setBaseTemplatePath(String baseTemplatePath) {
 		config.setBaseTemplatePath(baseTemplatePath);
 		return this;
 	}
-	
+
 	public String getBaseTemplatePath() {
 		return config.getBaseTemplatePath();
 	}
-	
+
 	public Engine setDatePattern(String datePattern) {
 		config.setDatePattern(datePattern);
 		return this;
 	}
-	
+
 	public String getDatePattern() {
 		return config.getDatePattern();
 	}
-	
+
 	public Engine setEncoding(String encoding) {
 		config.setEncoding(encoding);
 		return this;
 	}
-	
+
 	public String getEncoding() {
 		return config.getEncoding();
 	}
-	
+
 	/**
 	 * 设置 #number 指令与 Arith 中浮点数的舍入规则,默认为 RoundingMode.HALF_UP "四舍五入"
 	 */
@@ -609,7 +617,7 @@ public class Engine {
 		config.setRoundingMode(roundingMode);
 		return this;
 	}
-	
+
 	/**
 	 * Enjoy 模板引擎对 UTF-8 的 encoding 做过性能优化,某些罕见字符
 	 * 无法被编码,可以配置为 JdkEncoderFactory 解决问题:
@@ -619,7 +627,7 @@ public class Engine {
 		config.setEncoderFactory(encoderFactory);
 		return this;
 	}
-	
+
 	/**
 	 * 配置为 JdkEncoderFactory,支持 utf8mb4,支持 emoji 表情字符,
 	 * 支持各种罕见字符编码
@@ -628,20 +636,20 @@ public class Engine {
 		config.setEncoderFactory(new JdkEncoderFactory());
 		return this;
 	}
-	
+
 	public Engine setBufferSize(int bufferSize) {
 		config.setBufferSize(bufferSize);
 		return this;
 	}
-	
+
 	public Engine setReentrantBufferSize(int reentrantBufferSize) {
 		config.setReentrantBufferSize(reentrantBufferSize);
 		return this;
 	}
-	
+
 	/**
 	 * 设置开启压缩功能
-	 * 
+	 *
 	 * @param separator 压缩使用的分隔符,常用配置为 '\n' 与 ' '。
 	 *        如果模板中存在 javascript 脚本,需要配置为 '\n'
 	 *        两种配置的压缩率是完全一样的
@@ -649,17 +657,17 @@ public class Engine {
 	public Engine setCompressorOn(char separator) {
 		return setCompressor(new Compressor(separator));
 	}
-	
+
 	/**
 	 * 设置开启压缩功能。压缩分隔符使用默认值 '\n'
 	 */
 	public Engine setCompressorOn() {
 		return setCompressor(new Compressor());
 	}
-	
+
 	/**
 	 * 配置 Compressor 可对模板中的静态内容进行压缩
-	 * 
+	 *
 	 * 可通过该方法配置自定义的 Compressor 来代替系统默认实现,例如:
 	 *   engine.setCompressor(new MyCompressor());
 	 */
@@ -667,38 +675,38 @@ public class Engine {
 		config.setCompressor(compressor);
 		return this;
 	}
-	
+
 	/**
 	 * Engine 独立设置为 devMode 可以方便模板文件在修改后立即生效,
 	 * 但如果在 devMode 之下并不希望对 addSharedFunction(...),
 	 * 添加的模板进行是否被修改的检测可以通过此方法设置 false 参进去
-	 * 
+	 *
 	 * 注意:Engine 在生产环境下(devMode 为 false),该参数无效
 	 */
 	public Engine setReloadModifiedSharedFunctionInDevMode(boolean reloadModifiedSharedFunctionInDevMode) {
 		config.setReloadModifiedSharedFunctionInDevMode(reloadModifiedSharedFunctionInDevMode);
 		return this;
 	}
-	
+
 	public static void addExtensionMethod(Class<?> targetClass, Object objectOfExtensionClass) {
 		MethodKit.addExtensionMethod(targetClass, objectOfExtensionClass);
 	}
-	
+
 	public static void addExtensionMethod(Class<?> targetClass, Class<?> extensionClass) {
 		MethodKit.addExtensionMethod(targetClass, extensionClass);
 	}
-	
+
 	public static void removeExtensionMethod(Class<?> targetClass, Object objectOfExtensionClass) {
 		MethodKit.removeExtensionMethod(targetClass, objectOfExtensionClass);
 	}
-	
+
 	public static void removeExtensionMethod(Class<?> targetClass, Class<?> extensionClass) {
 		MethodKit.removeExtensionMethod(targetClass, extensionClass);
 	}
-	
+
 	/**
 	 * 添加 FieldGetter 实现类到指定的位置
-	 * 
+	 *
 	 * 系统当前默认 FieldGetter 实现类及其位置如下:
 	 * GetterMethodFieldGetter  ---> 调用 getter 方法取值
 	 * RealFieldGetter			---> 直接获取 public 型的 object.field 值
@@ -706,11 +714,11 @@ public class Engine {
 	 * RecordFieldGetter			---> 调用 Record.get(String) 方法取值
 	 * MapFieldGetter			---> 调用 Map.get(String) 方法取值
 	 * ArrayLengthGetter			---> 获取数组长度
-	 * 
+	 *
 	 * 根据以上次序,如果要插入 IsMethodFieldGetter 到 GetterMethodFieldGetter
 	 * 之后的代码如下:
 	 * Engine.addFieldGetter(1, new IsMethodFieldGetter());
-	 * 
+	 *
 	 * 注:IsMethodFieldGetter 系统已经提供,只是默认没有启用。该实现类通过调用
 	 *    target.isXxx() 方法获取 target.xxx 表达式的值,其中 isXxx() 返回值
 	 *    必须是 Boolean/boolean 类型才会被调用
@@ -718,26 +726,26 @@ public class Engine {
 	public static void addFieldGetter(int index, FieldGetter fieldGetter) {
 		FieldKit.addFieldGetter(index, fieldGetter);
 	}
-	
+
 	public static void addFieldGetterToLast(FieldGetter fieldGetter) {
 		FieldKit.addFieldGetterToLast(fieldGetter);
 	}
-	
+
 	public static void addFieldGetterToFirst(FieldGetter fieldGetter) {
 		FieldKit.addFieldGetterToFirst(fieldGetter);
 	}
-	
+
 	public static void removeFieldGetter(Class<? extends FieldGetter> fieldGetterClass) {
 		FieldKit.removeFieldGetter(fieldGetterClass);
 	}
-	
+
 	public static void setFastFieldKeyBuilder(boolean enable) {
 		FieldKeyBuilder.setFastFieldKeyBuilder(enable);
 	}
-	
+
 	/**
 	 * 设置极速模式
-	 * 
+	 *
 	 * 极速模式将生成代理对象来消除 java.lang.reflect.Method.invoke(...) 调用,
 	 * 性能提升 12.9%
 	 */
@@ -745,7 +753,7 @@ public class Engine {
 		FieldKit.setFastMode(fastMode);
 		FieldKeyBuilder.setFastFieldKeyBuilder(fastMode);
 	}
-	
+
 	/**
 	 * 设置为 true 支持表达式、变量名、方法名、模板函数名使用中文
 	 */

+ 73 - 66
src/main/java/com/jfinal/template/EngineConfig.java

@@ -50,54 +50,54 @@ import com.jfinal.template.stat.ast.Output;
  * EngineConfig
  */
 public class EngineConfig {
-	
+
 	public static final String DEFAULT_ENCODING = "UTF-8";
-	
+
 	WriterBuffer writerBuffer = new WriterBuffer();
-	
+
 	Compressor compressor = null;
-	
+
 	private Map<String, Define> sharedFunctionMap = createSharedFunctionMap();		// new HashMap<String, Define>(512, 0.25F);
 	private List<ISource> sharedFunctionSourceList = new ArrayList<ISource>();		// for devMode only
-	
+
 	Map<String, Object> sharedObjectMap = null;
-	
+
 	private OutputDirectiveFactory outputDirectiveFactory = OutputDirectiveFactory.me;
 	private ISourceFactory sourceFactory = new FileSourceFactory();
 	private Map<String, Class<? extends Directive>> directiveMap = new HashMap<String, Class<? extends Directive>>(64, 0.5F);
 	private SharedMethodKit sharedMethodKit = new SharedMethodKit();
-	
+
 	// 保留指令所在行空白字符的指令
 	private Set<String> keepLineBlankDirectives = new HashSet<>();
-	
+
 	private boolean devMode = false;
 	private boolean reloadModifiedSharedFunctionInDevMode = true;
 	private String baseTemplatePath = null;
 	private String encoding = DEFAULT_ENCODING;
 	private String datePattern = "yyyy-MM-dd HH:mm";
-	
+
 	// 浮点数输出与运算时使用的舍入模式,默认值为 "四舍五入"
 	private RoundingMode roundingMode = RoundingMode.HALF_UP;
-	
+
 	public EngineConfig() {
 		// 内置指令 #() 与 #include() 需要配置,保留指令所在行前后空白字符以及行尾换行字符 '\n'
 		setKeepLineBlank("output", true);
 		setKeepLineBlank("include", true);
-		
+
 		// Add official directive of Template Engine
 		addDirective("render", RenderDirective.class, true);
 		addDirective("date", DateDirective.class, true);
 		addDirective("escape", EscapeDirective.class, true);
 		addDirective("random", RandomDirective.class, true);
 		addDirective("number", NumberDirective.class, true);
-		
+
 		addDirective("call", CallDirective.class, false);
 		addDirective("string", StringDirective.class, false);
-		
+
 		// Add official shared method of Template Engine
 		addSharedMethod(new SharedMethodLib());
 	}
-	
+
 	/**
 	 * Add shared function with file
 	 */
@@ -107,7 +107,7 @@ public class EngineConfig {
 		ISource source = sourceFactory.getSource(baseTemplatePath, fileName, encoding);
 		doAddSharedFunction(source, fileName);
 	}
-	
+
 	private synchronized void doAddSharedFunction(ISource source, String fileName) {
 		Env env = new Env(this);
 		new Parser(env, source.getContent(), fileName).parse();
@@ -117,7 +117,7 @@ public class EngineConfig {
 			env.addSource(source);
 		}
 	}
-	
+
 	/**
 	 * Add shared function with files
 	 */
@@ -126,7 +126,7 @@ public class EngineConfig {
 			addSharedFunction(fileName);
 		}
 	}
-	
+
 	/**
 	 * Add shared function by string content
 	 */
@@ -136,7 +136,7 @@ public class EngineConfig {
 		StringSource stringSource = new StringSource(content, false);
 		doAddSharedFunction(stringSource, null);
 	}
-	
+
 	/**
 	 * Add shared function by ISource
 	 */
@@ -144,7 +144,7 @@ public class EngineConfig {
 		String fileName = source instanceof FileSource ? ((FileSource)source).getFileName() : null;
 		doAddSharedFunction(source, fileName);
 	}
-	
+
 	private void addToSharedFunctionMap(Map<String, Define> sharedFunctionMap, Env env) {
 		Map<String, Define> funcMap = env.getFunctionMap();
 		for (Entry<String, Define> e : funcMap.entrySet()) {
@@ -158,7 +158,7 @@ public class EngineConfig {
 			sharedFunctionMap.put(e.getKey(), func);
 		}
 	}
-	
+
 	/**
 	 * Get shared function by Env
 	 */
@@ -168,16 +168,16 @@ public class EngineConfig {
 			/**
 			 * 如果 func 最初未定义,但后续在共享模板文件中又被添加进来
 			 * 此时在本 if 分支中无法被感知,仍然返回了 null
-			 * 
+			 *
 			 * 但共享模板文件会在后续其它的 func 调用时被感知修改并 reload
 			 * 所以本 if 分支不考虑处理模板文件中追加 #define 的情况
-			 * 
+			 *
 			 * 如果要处理,只能是每次在 func 为 null 时,判断 sharedFunctionSourceList
 			 * 中的模板是否被修改过,再重新加载,不优雅
 			 */
 			return null;
 		}
-		
+
 		if (devMode && reloadModifiedSharedFunctionInDevMode) {
 			if (func.isSourceModifiedForDevMode()) {
 				synchronized (this) {
@@ -191,10 +191,10 @@ public class EngineConfig {
 		}
 		return func;
 	}
-	
+
 	/**
 	 * Reload shared function source list
-	 * 
+	 *
 	 * devMode 要照顾到 sharedFunctionFiles,所以暂不提供
 	 * removeSharedFunction(String functionName) 功能
 	 * 开发者可直接使用模板注释功能将不需要的 function 直接注释掉
@@ -204,7 +204,7 @@ public class EngineConfig {
 		for (int i = 0, size = sharedFunctionSourceList.size(); i < size; i++) {
 			ISource source = sharedFunctionSourceList.get(i);
 			String fileName = source instanceof FileSource ? ((FileSource)source).getFileName() : null;
-			
+
 			Env env = new Env(this);
 			new Parser(env, source.getContent(), fileName).parse();
 			addToSharedFunctionMap(newMap, env);
@@ -214,11 +214,11 @@ public class EngineConfig {
 		}
 		this.sharedFunctionMap = newMap;
 	}
-	
+
 	private Map<String, Define> createSharedFunctionMap() {
 		return new HashMap<String, Define>(512, 0.25F);
 	}
-	
+
 	public synchronized void addSharedObject(String name, Object object) {
 		if (sharedObjectMap == null) {
 			sharedObjectMap = new HashMap<String, Object>(64, 0.25F);
@@ -227,17 +227,17 @@ public class EngineConfig {
 		}
 		sharedObjectMap.put(name, object);
 	}
-	
+
 	public Map<String, Object> getSharedObjectMap() {
 		return sharedObjectMap;
 	}
-	
+
 	public synchronized void removeSharedObject(String name) {
 		if (sharedObjectMap != null) {
 			sharedObjectMap.remove(name);
 		}
 	}
-	
+
 	/**
 	 * Set output directive factory
 	 */
@@ -247,22 +247,22 @@ public class EngineConfig {
 		}
 		this.outputDirectiveFactory = outputDirectiveFactory;
 	}
-	
+
 	public Output getOutputDirective(ExprList exprList, Location location) {
 		return outputDirectiveFactory.getOutputDirective(exprList, location);
 	}
-	
+
 	/**
 	 * Invoked by Engine only
 	 */
 	void setDevMode(boolean devMode) {
 		this.devMode = devMode;
 	}
-	
+
 	public boolean isDevMode() {
 		return devMode;
 	}
-	
+
 	/**
 	 * Invoked by Engine only
 	 */
@@ -272,11 +272,11 @@ public class EngineConfig {
 		}
 		this.sourceFactory = sourceFactory;
 	}
-	
+
 	public ISourceFactory getSourceFactory() {
 		return sourceFactory;
 	}
-	
+
 	public void setBaseTemplatePath(String baseTemplatePath) {
 		// 使用 ClassPathSourceFactory 时,允许 baseTemplatePath 为 null 值
 		if (baseTemplatePath == null) {
@@ -295,33 +295,33 @@ public class EngineConfig {
 		}
 		this.baseTemplatePath = baseTemplatePath;
 	}
-	
+
 	public String getBaseTemplatePath() {
 		return baseTemplatePath;
 	}
-	
+
 	public void setEncoding(String encoding) {
 		if (StrKit.isBlank(encoding)) {
 			throw new IllegalArgumentException("encoding can not be blank");
 		}
 		this.encoding = encoding;
-		
+
 		writerBuffer.setEncoding(encoding);		// 间接设置 EncoderFactory.encoding
 	}
-	
+
 	public void setEncoderFactory(EncoderFactory encoderFactory) {
 		writerBuffer.setEncoderFactory(encoderFactory);
 		writerBuffer.setEncoding(encoding);		// 间接设置 EncoderFactory.encoding
 	}
-	
+
 	public void setBufferSize(int bufferSize) {
 		writerBuffer.setBufferSize(bufferSize);
 	}
-	
+
 	public void setReentrantBufferSize(int reentrantBufferSize) {
 		writerBuffer.setReentrantBufferSize(reentrantBufferSize);
 	}
-	
+
 	/**
 	 * 配置自己的 WriterBuffer 实现,配置方法:
 	 * engine.getEngineConfig().setWriterBuffer(...);
@@ -330,26 +330,26 @@ public class EngineConfig {
 		Objects.requireNonNull(writerBuffer, "writerBuffer can not be null");
 		this.writerBuffer = writerBuffer;
 	}
-	
+
 	public String getEncoding() {
 		return encoding;
 	}
-	
+
 	public void setDatePattern(String datePattern) {
 		if (StrKit.isBlank(datePattern)) {
 			throw new IllegalArgumentException("datePattern can not be blank");
 		}
 		this.datePattern = datePattern;
 	}
-	
+
 	public String getDatePattern() {
 		return datePattern;
 	}
-	
+
 	public void setReloadModifiedSharedFunctionInDevMode(boolean reloadModifiedSharedFunctionInDevMode) {
 		this.reloadModifiedSharedFunctionInDevMode = reloadModifiedSharedFunctionInDevMode;
 	}
-	
+
 	public synchronized void addDirective(String directiveName, Class<? extends Directive> directiveClass, boolean keepLineBlank) {
 		if (StrKit.isBlank(directiveName)) {
 			throw new IllegalArgumentException("directive name can not be blank");
@@ -360,26 +360,26 @@ public class EngineConfig {
 		if (directiveMap.containsKey(directiveName)) {
 			throw new IllegalArgumentException("directive already exists : " + directiveName);
 		}
-		
+
 		directiveMap.put(directiveName, directiveClass);
 		if (keepLineBlank) {
 			keepLineBlankDirectives.add(directiveName);
 		}
 	}
-	
+
 	public void addDirective(String directiveName, Class<? extends Directive> directiveClass) {
 		addDirective(directiveName, directiveClass, false);
 	}
-	
+
 	public Class<? extends Directive> getDirective(String directiveName) {
 		return directiveMap.get(directiveName);
 	}
-	
+
 	public void removeDirective(String directiveName) {
 		directiveMap.remove(directiveName);
 		keepLineBlankDirectives.remove(directiveName);
 	}
-	
+
 	public void setKeepLineBlank(String directiveName, boolean keepLineBlank) {
 		if (keepLineBlank) {
 			keepLineBlankDirectives.add(directiveName);
@@ -387,65 +387,72 @@ public class EngineConfig {
 			keepLineBlankDirectives.remove(directiveName);
 		}
 	}
-	
+
 	public Set<String> getKeepLineBlankDirectives() {
 		return keepLineBlankDirectives;
 	}
-	
+
 	/**
 	 * Add shared method from object
 	 */
 	public void addSharedMethod(Object sharedMethodFromObject) {
 		sharedMethodKit.addSharedMethod(sharedMethodFromObject);
 	}
-	
+
 	/**
 	 * Add shared method from class
 	 */
 	public void addSharedMethod(Class<?> sharedMethodFromClass) {
 		sharedMethodKit.addSharedMethod(sharedMethodFromClass);
 	}
-	
+
 	/**
 	 * Add shared static method of Class
 	 */
 	public void addSharedStaticMethod(Class<?> sharedStaticMethodFromClass) {
 		sharedMethodKit.addSharedStaticMethod(sharedStaticMethodFromClass);
 	}
-	
+
 	/**
 	 * Remove shared Method with method name
 	 */
 	public void removeSharedMethod(String methodName) {
 		sharedMethodKit.removeSharedMethod(methodName);
 	}
-	
+
 	/**
 	 * Remove shared Method of the Class
 	 */
 	public void removeSharedMethod(Class<?> sharedClass) {
 		sharedMethodKit.removeSharedMethod(sharedClass);
 	}
-	
+
 	/**
 	 * Remove shared Method
 	 */
 	public void removeSharedMethod(Method method) {
 		sharedMethodKit.removeSharedMethod(method);
 	}
-	
+
+	/**
+	 * Remove shared Method
+	 */
+	public void removeSharedMethod(String methodName, Class<?>... paraTypes) {
+		sharedMethodKit.removeSharedMethod(methodName, paraTypes);
+	}
+
 	public SharedMethodKit getSharedMethodKit() {
 		return sharedMethodKit;
 	}
-	
+
 	public void setCompressor(Compressor compressor) {
 		this.compressor = compressor;
 	}
-	
+
 	public Compressor getCompressor() {
 		return compressor;
 	}
-	
+
 	/**
 	 * 设置 #number 指令与 Arith 中浮点数的舍入规则,默认为 RoundingMode.HALF_UP "四舍五入"
 	 */
@@ -453,7 +460,7 @@ public class EngineConfig {
 		this.roundingMode = roundingMode;
 		Arith.setBigDecimalDivideRoundingMode(roundingMode);
 	}
-	
+
 	public RoundingMode getRoundingMode() {
 		return roundingMode;
 	}