Freemarker源码分析(5)cache包中其他的类
2021/11/8 1:10:15
本文主要是介绍Freemarker源码分析(5)cache包中其他的类,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
2021SC@SDUSC
Freemarker源码分析(5)cache包中其他的类
- Freemarker源码分析(5)cache包中其他的类
- _CacheAPI类
- TemplateCache类
- URLTemplateSource类
- TemplateLookupStrategy类
- TemplateLookupContext类
- TemplateLookupResult类
Freemarker源码分析(5)cache包中其他的类
总览
_CacheAPI类
代码
public final class _CacheAPI { private _CacheAPI() { // 不必实例化 } public static String toRootBasedName(TemplateNameFormat templateNameFormat, String baseName, String targetName) throws MalformedTemplateNameException { return templateNameFormat.toRootBasedName(baseName, targetName); } public static String normalizeRootBasedName(TemplateNameFormat templateNameFormat, String name) throws MalformedTemplateNameException { return templateNameFormat.normalizeRootBasedName(name); } public static String rootBasedNameToAbsoluteName(TemplateNameFormat templateNameFormat, String rootBasedName) throws MalformedTemplateNameException { return templateNameFormat.rootBasedNameToAbsoluteName(rootBasedName); } }
作用:这个类是为了解决Java中缺少模块系统的问题,也就是说,其他FreeMarker包可以访问这个包中用户不应该访问的内容。(此类仅供内部使用)
TemplateCache类
代码
public class TemplateCache { public static final long DEFAULT_TEMPLATE_UPDATE_DELAY_MILLIS = 5000L; private static final String ASTERISKSTR = "*"; private static final char ASTERISK = '*'; private static final char SLASH = '/'; private static final String LOCALE_PART_SEPARATOR = "_"; private static final Logger LOG = Logger.getLogger("freemarker.cache"); private final TemplateLoader templateLoader; private final CacheStorage storage; private final TemplateLookupStrategy templateLookupStrategy; private final TemplateNameFormat templateNameFormat; private final TemplateConfigurationFactory templateConfigurations; private final boolean isStorageConcurrent; private long updateDelay = DEFAULT_TEMPLATE_UPDATE_DELAY_MILLIS; private boolean localizedLookup = true; private Configuration config; @Deprecated public TemplateCache() { this(_TemplateAPI.createDefaultTemplateLoader(Configuration.VERSION_2_3_0)); } @Deprecated public TemplateCache(TemplateLoader templateLoader) { this(templateLoader, (Configuration) null); } @Deprecated public TemplateCache(TemplateLoader templateLoader, CacheStorage cacheStorage) { this(templateLoader, cacheStorage, null); } public TemplateCache(TemplateLoader templateLoader, Configuration config) { this(templateLoader, _TemplateAPI.createDefaultCacheStorage(Configuration.VERSION_2_3_0), config); } public TemplateCache(TemplateLoader templateLoader, CacheStorage cacheStorage, Configuration config) { this(templateLoader, cacheStorage, _TemplateAPI.getDefaultTemplateLookupStrategy(Configuration.VERSION_2_3_0), _TemplateAPI.getDefaultTemplateNameFormat(Configuration.VERSION_2_3_0), config); } public TemplateCache(TemplateLoader templateLoader, CacheStorage cacheStorage, TemplateLookupStrategy templateLookupStrategy, TemplateNameFormat templateNameFormat, Configuration config) { this(templateLoader, cacheStorage, templateLookupStrategy, templateNameFormat, null, config); } public TemplateCache(TemplateLoader templateLoader, CacheStorage cacheStorage, TemplateLookupStrategy templateLookupStrategy, TemplateNameFormat templateNameFormat, TemplateConfigurationFactory templateConfigurations, Configuration config) { this.templateLoader = templateLoader; NullArgumentException.check("cacheStorage", cacheStorage); this.storage = cacheStorage; isStorageConcurrent = cacheStorage instanceof ConcurrentCacheStorage && ((ConcurrentCacheStorage) cacheStorage).isConcurrent(); NullArgumentException.check("templateLookupStrategy", templateLookupStrategy); this.templateLookupStrategy = templateLookupStrategy; NullArgumentException.check("templateNameFormat", templateNameFormat); this.templateNameFormat = templateNameFormat; // Can be null this.templateConfigurations = templateConfigurations; this.config = config; } @Deprecated public void setConfiguration(Configuration config) { this.config = config; clear(); } public TemplateLoader getTemplateLoader() { return templateLoader; } public CacheStorage getCacheStorage() { return storage; } /** * @since 2.3.22 */ public TemplateLookupStrategy getTemplateLookupStrategy() { return templateLookupStrategy; } public TemplateNameFormat getTemplateNameFormat() { return templateNameFormat; } public TemplateConfigurationFactory getTemplateConfigurations() { return templateConfigurations; } public MaybeMissingTemplate getTemplate(String name, Locale locale, Object customLookupCondition, String encoding, boolean parseAsFTL) throws IOException { NullArgumentException.check("name", name); NullArgumentException.check("locale", locale); NullArgumentException.check("encoding", encoding); try { name = templateNameFormat.normalizeRootBasedName(name); } catch (MalformedTemplateNameException e) { // If we don't have to emulate backward compatible behavior, then just rethrow it: if (templateNameFormat != TemplateNameFormat.DEFAULT_2_3_0 || config.getIncompatibleImprovements().intValue() >= _TemplateAPI.VERSION_INT_2_4_0) { throw e; } return new MaybeMissingTemplate(null, e); } if (templateLoader == null) { return new MaybeMissingTemplate(name, "The TemplateLoader was null."); } Template template = getTemplateInternal(name, locale, customLookupCondition, encoding, parseAsFTL); return template != null ? new MaybeMissingTemplate(template) : new MaybeMissingTemplate(name, (String) null); } @Deprecated public Template getTemplate(String name, Locale locale, String encoding, boolean parseAsFTL) throws IOException { return getTemplate(name, locale, null, encoding, parseAsFTL).getTemplate(); } @Deprecated protected static TemplateLoader createLegacyDefaultTemplateLoader() { return _TemplateAPI.createDefaultTemplateLoader(Configuration.VERSION_2_3_0); } private Template getTemplateInternal( final String name, final Locale locale, final Object customLookupCondition, final String encoding, final boolean parseAsFTL) throws IOException { final boolean debug = LOG.isDebugEnabled(); final String debugName = debug ? buildDebugName(name, locale, customLookupCondition, encoding, parseAsFTL) : null; final TemplateKey tk = new TemplateKey(name, locale, customLookupCondition, encoding, parseAsFTL); CachedTemplate cachedTemplate; if (isStorageConcurrent) { cachedTemplate = (CachedTemplate) storage.get(tk); } else { synchronized (storage) { cachedTemplate = (CachedTemplate) storage.get(tk); } } final long now = System.currentTimeMillis(); long lastModified = -1L; boolean rethrown = false; TemplateLookupResult newLookupResult = null; try { if (cachedTemplate != null) { if (now - cachedTemplate.lastChecked < updateDelay) { if (debug) { LOG.debug(debugName + " cached copy not yet stale; using cached."); } // Can be null, indicating a cached negative lookup Object t = cachedTemplate.templateOrException; if (t instanceof Template || t == null) { return (Template) t; } else if (t instanceof RuntimeException) { throwLoadFailedException((RuntimeException) t); } else if (t instanceof IOException) { rethrown = true; throwLoadFailedException((IOException) t); } throw new BugException("t is " + t.getClass().getName()); } cachedTemplate = cachedTemplate.cloneCachedTemplate(); cachedTemplate.lastChecked = now; newLookupResult = lookupTemplate(name, locale, customLookupCondition); // Template source was removed if (!newLookupResult.isPositive()) { if (debug) { LOG.debug(debugName + " no source found."); } storeNegativeLookup(tk, cachedTemplate, null); return null; } final Object newLookupResultSource = newLookupResult.getTemplateSource(); lastModified = templateLoader.getLastModified(newLookupResultSource); boolean lastModifiedNotChanged = lastModified == cachedTemplate.lastModified; boolean sourceEquals = newLookupResultSource.equals(cachedTemplate.source); if (lastModifiedNotChanged && sourceEquals) { if (debug) { LOG.debug(debugName + ": using cached since " + newLookupResultSource + " hasn't changed."); } storeCached(tk, cachedTemplate); return (Template) cachedTemplate.templateOrException; } else if (debug) { if (!sourceEquals) { LOG.debug("Updating source because: " + "sourceEquals=" + sourceEquals + ", newlyFoundSource=" + StringUtil.jQuoteNoXSS(newLookupResultSource) + ", cached.source=" + StringUtil.jQuoteNoXSS(cachedTemplate.source)); } else if (!lastModifiedNotChanged) { LOG.debug("Updating source because: " + "lastModifiedNotChanged=" + lastModifiedNotChanged + ", cached.lastModified=" + cachedTemplate.lastModified + " != source.lastModified=" + lastModified); } } } else { if (debug) { LOG.debug("Couldn't find template in cache for " + debugName + "; will try to load it."); } cachedTemplate = new CachedTemplate(); cachedTemplate.lastChecked = now; newLookupResult = lookupTemplate(name, locale, customLookupCondition); if (!newLookupResult.isPositive()) { storeNegativeLookup(tk, cachedTemplate, null); return null; } cachedTemplate.lastModified = lastModified = Long.MIN_VALUE; } Object source = newLookupResult.getTemplateSource(); cachedTemplate.source = source; if (debug) { LOG.debug("Loading template for " + debugName + " from " + StringUtil.jQuoteNoXSS(source)); } lastModified = lastModified == Long.MIN_VALUE ? templateLoader.getLastModified(source) : lastModified; Template template = loadTemplate( templateLoader, source, name, newLookupResult.getTemplateSourceName(), locale, customLookupCondition, encoding, parseAsFTL); cachedTemplate.templateOrException = template; cachedTemplate.lastModified = lastModified; storeCached(tk, cachedTemplate); return template; } catch (RuntimeException e) { if (cachedTemplate != null) { storeNegativeLookup(tk, cachedTemplate, e); } throw e; } catch (IOException e) { if (!rethrown) { storeNegativeLookup(tk, cachedTemplate, e); } throw e; } finally { if (newLookupResult != null && newLookupResult.isPositive()) { templateLoader.closeTemplateSource(newLookupResult.getTemplateSource()); } } } private static final Method INIT_CAUSE = getInitCauseMethod(); private static final Method getInitCauseMethod() { try { return Throwable.class.getMethod("initCause", new Class[] { Throwable.class }); } catch (NoSuchMethodException e) { return null; } } private IOException newIOException(String message, Throwable cause) { if (cause == null) { return new IOException(message); } IOException ioe; if (INIT_CAUSE != null) { ioe = new IOException(message); try { INIT_CAUSE.invoke(ioe, cause); } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { throw new UndeclaredThrowableException(ex); } } else { ioe = new IOException(message + "\nCaused by: " + cause.getClass().getName() + ": " + cause.getMessage()); } return ioe; } private void throwLoadFailedException(Throwable e) throws IOException { throw newIOException("There was an error loading the " + "template on an earlier attempt; see cause exception.", e); } private void storeNegativeLookup(TemplateKey tk, CachedTemplate cachedTemplate, Exception e) { cachedTemplate.templateOrException = e; cachedTemplate.source = null; cachedTemplate.lastModified = 0L; storeCached(tk, cachedTemplate); } private void storeCached(TemplateKey tk, CachedTemplate cachedTemplate) { if (isStorageConcurrent) { storage.put(tk, cachedTemplate); } else { synchronized (storage) { storage.put(tk, cachedTemplate); } } } private Template loadTemplate( final TemplateLoader templateLoader, final Object source, final String name, final String sourceName, Locale locale, final Object customLookupCondition, String initialEncoding, final boolean parseAsFTL) throws IOException { final TemplateConfiguration tc; try { tc = templateConfigurations != null ? templateConfigurations.get(sourceName, source) : null; } catch (TemplateConfigurationFactoryException e) { throw newIOException("Error while getting TemplateConfiguration; see cause exception.", e); } if (tc != null) { // TC.{encoding,locale} is stronger than the cfg.getTemplate arguments by design. if (tc.isEncodingSet()) { initialEncoding = tc.getEncoding(); } if (tc.isLocaleSet()) { locale = tc.getLocale(); } } Template template; { if (parseAsFTL) { try { try (Reader reader = templateLoader.getReader(source, initialEncoding)) { template = new Template(name, sourceName, reader, config, tc, initialEncoding); } } catch (Template.WrongEncodingException wee) { String actualEncoding = wee.getTemplateSpecifiedEncoding(); if (LOG.isDebugEnabled()) { LOG.debug("Initial encoding \"" + initialEncoding + "\" was incorrect, re-reading with \"" + actualEncoding + "\". Template: " + sourceName); } try (Reader reader = templateLoader.getReader(source, actualEncoding)) { template = new Template(name, sourceName, reader, config, tc, actualEncoding); } } } else { final StringWriter sw = new StringWriter(); final char[] buf = new char[4096]; try (Reader reader = templateLoader.getReader(source, initialEncoding)) { fetchChars: while (true) { int charsRead = reader.read(buf); if (charsRead > 0) { sw.write(buf, 0, charsRead); } else if (charsRead < 0) { break fetchChars; } } } template = Template.getPlainTextTemplate(name, sourceName, sw.toString(), config); template.setEncoding(initialEncoding); } } if (tc != null) { tc.apply(template); } template.setLocale(locale); template.setCustomLookupCondition(customLookupCondition); return template; } public long getDelay() { synchronized (this) { return updateDelay; } } public void setDelay(long delay) { // synchronized was moved here so that we don't advertise that it's thread-safe, as it's not. synchronized (this) { this.updateDelay = delay; } } public boolean getLocalizedLookup() { // synchronized was moved here so that we don't advertise that it's thread-safe, as it's not. synchronized (this) { return localizedLookup; } } public void setLocalizedLookup(boolean localizedLookup) { // synchronized was moved here so that we don't advertise that it's thread-safe, as it's not. synchronized (this) { if (this.localizedLookup != localizedLookup) { this.localizedLookup = localizedLookup; clear(); } } } public void clear() { synchronized (storage) { storage.clear(); if (templateLoader instanceof StatefulTemplateLoader) { ((StatefulTemplateLoader) templateLoader).resetState(); } } } /** * Same as {@link #removeTemplate(String, Locale, Object, String, boolean)} with {@code null} * {@code customLookupCondition}. */ public void removeTemplate( String name, Locale locale, String encoding, boolean parse) throws IOException { removeTemplate(name, locale, null, encoding, parse); } public void removeTemplate( String name, Locale locale, Object customLookupCondition, String encoding, boolean parse) throws IOException { if (name == null) { throw new IllegalArgumentException("Argument \"name\" can't be null"); } if (locale == null) { throw new IllegalArgumentException("Argument \"locale\" can't be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument \"encoding\" can't be null"); } name = templateNameFormat.normalizeRootBasedName(name); if (name != null && templateLoader != null) { boolean debug = LOG.isDebugEnabled(); String debugName = debug ? buildDebugName(name, locale, customLookupCondition, encoding, parse) : null; TemplateKey tk = new TemplateKey(name, locale, customLookupCondition, encoding, parse); if (isStorageConcurrent) { storage.remove(tk); } else { synchronized (storage) { storage.remove(tk); } } if (debug) { LOG.debug(debugName + " was removed from the cache, if it was there"); } } } private String buildDebugName(String name, Locale locale, Object customLookupCondition, String encoding, boolean parse) { return StringUtil.jQuoteNoXSS(name) + "(" + StringUtil.jQuoteNoXSS(locale) + (customLookupCondition != null ? ", cond=" + StringUtil.jQuoteNoXSS(customLookupCondition) : "") + ", " + encoding + (parse ? ", parsed)" : ", unparsed]"); } @Deprecated public static String getFullTemplatePath(Environment env, String baseName, String targetName) { try { return env.toFullTemplateName(baseName, targetName); } catch (MalformedTemplateNameException e) { throw new IllegalArgumentException(e.getMessage()); } } private TemplateLookupResult lookupTemplate(String name, Locale locale, Object customLookupCondition) throws IOException { final TemplateLookupResult lookupResult = templateLookupStrategy.lookup( new TemplateCacheTemplateLookupContext(name, locale, customLookupCondition)); if (lookupResult == null) { throw new NullPointerException("Lookup result shouldn't be null"); } return lookupResult; } private TemplateLookupResult lookupTemplateWithAcquisitionStrategy(String path) throws IOException { int asterisk = path.indexOf(ASTERISK); // Shortcut in case there is no acquisition if (asterisk == -1) { return TemplateLookupResult.from(path, findTemplateSource(path)); } StringTokenizer tok = new StringTokenizer(path, "/"); int lastAsterisk = -1; List tokpath = new ArrayList(); while (tok.hasMoreTokens()) { String pathToken = tok.nextToken(); if (pathToken.equals(ASTERISKSTR)) { if (lastAsterisk != -1) { tokpath.remove(lastAsterisk); } lastAsterisk = tokpath.size(); } tokpath.add(pathToken); } if (lastAsterisk == -1) { // if there was no real "*" step after all return TemplateLookupResult.from(path, findTemplateSource(path)); } String basePath = concatPath(tokpath, 0, lastAsterisk); String resourcePath = concatPath(tokpath, lastAsterisk + 1, tokpath.size()); if (resourcePath.endsWith("/")) { resourcePath = resourcePath.substring(0, resourcePath.length() - 1); } StringBuilder buf = new StringBuilder(path.length()).append(basePath); int l = basePath.length(); for (; ; ) { String fullPath = buf.append(resourcePath).toString(); Object templateSource = findTemplateSource(fullPath); if (templateSource != null) { return TemplateLookupResult.from(fullPath, templateSource); } if (l == 0) { return TemplateLookupResult.createNegativeResult(); } l = basePath.lastIndexOf(SLASH, l - 2) + 1; buf.setLength(l); } } private Object findTemplateSource(String path) throws IOException { final Object result = templateLoader.findTemplateSource(path); if (LOG.isDebugEnabled()) { LOG.debug("TemplateLoader.findTemplateSource(" + StringUtil.jQuote(path) + "): " + (result == null ? "Not found" : "Found")); } return modifyForConfIcI(result); } private Object modifyForConfIcI(Object templateSource) { if (templateSource == null) return null; if (config.getIncompatibleImprovements().intValue() < _TemplateAPI.VERSION_INT_2_3_21) { return templateSource; } if (templateSource instanceof URLTemplateSource) { URLTemplateSource urlTemplateSource = (URLTemplateSource) templateSource; if (urlTemplateSource.getUseCaches() == null) { // It was left unset urlTemplateSource.setUseCaches(false); } } else if (templateSource instanceof MultiSource) { modifyForConfIcI(((MultiSource) templateSource).getWrappedSource()); } return templateSource; } private String concatPath(List path, int from, int to) { StringBuilder buf = new StringBuilder((to - from) * 16); for (int i = from; i < to; ++i) { buf.append(path.get(i)).append('/'); } return buf.toString(); } private static final class TemplateKey { private final String name; private final Locale locale; private final Object customLookupCondition; private final String encoding; private final boolean parse; TemplateKey(String name, Locale locale, Object customLookupCondition, String encoding, boolean parse) { this.name = name; this.locale = locale; this.customLookupCondition = customLookupCondition; this.encoding = encoding; this.parse = parse; } @Override public boolean equals(Object o) { if (o instanceof TemplateKey) { TemplateKey tk = (TemplateKey) o; return parse == tk.parse && name.equals(tk.name) && locale.equals(tk.locale) && nullSafeEquals(customLookupCondition, tk.customLookupCondition) && encoding.equals(tk.encoding); } return false; } private boolean nullSafeEquals(Object o1, Object o2) { return o1 != null ? (o2 != null ? o1.equals(o2) : false) : o2 == null; } @Override public int hashCode() { return name.hashCode() ^ locale.hashCode() ^ encoding.hashCode() ^ (customLookupCondition != null ? customLookupCondition.hashCode() : 0) ^ Boolean.valueOf(!parse).hashCode(); } } private static final class CachedTemplate implements Cloneable, Serializable { private static final long serialVersionUID = 1L; Object templateOrException; Object source; long lastChecked; long lastModified; public CachedTemplate cloneCachedTemplate() { try { return (CachedTemplate) super.clone(); } catch (CloneNotSupportedException e) { throw new UndeclaredThrowableException(e); } } } private class TemplateCacheTemplateLookupContext extends TemplateLookupContext { TemplateCacheTemplateLookupContext(String templateName, Locale templateLocale, Object customLookupCondition) { super(templateName, localizedLookup ? templateLocale : null, customLookupCondition); } @Override public TemplateLookupResult lookupWithAcquisitionStrategy(String name) throws IOException { // Only one of the possible ways of making a name non-normalized, but is the easiest mistake to do: if (name.startsWith("/")) { throw new IllegalArgumentException("Non-normalized name, starts with \"/\": " + name); } return TemplateCache.this.lookupTemplateWithAcquisitionStrategy(name); } @Override public TemplateLookupResult lookupWithLocalizedThenAcquisitionStrategy(final String templateName, final Locale templateLocale) throws IOException { if (templateLocale == null) { return lookupWithAcquisitionStrategy(templateName); } int lastDot = templateName.lastIndexOf('.'); String prefix = lastDot == -1 ? templateName : templateName.substring(0, lastDot); String suffix = lastDot == -1 ? "" : templateName.substring(lastDot); String localeName = LOCALE_PART_SEPARATOR + templateLocale.toString(); StringBuilder buf = new StringBuilder(templateName.length() + localeName.length()); buf.append(prefix); tryLocaleNameVariations: while (true) { buf.setLength(prefix.length()); String path = buf.append(localeName).append(suffix).toString(); TemplateLookupResult lookupResult = lookupWithAcquisitionStrategy(path); if (lookupResult.isPositive()) { return lookupResult; } int lastUnderscore = localeName.lastIndexOf('_'); if (lastUnderscore == -1) { break tryLocaleNameVariations; } localeName = localeName.substring(0, lastUnderscore); } return createNegativeLookupResult(); } } public final static class MaybeMissingTemplate { private final Template template; private final String missingTemplateNormalizedName; private final String missingTemplateReason; private final MalformedTemplateNameException missingTemplateCauseException; private MaybeMissingTemplate(Template template) { this.template = template; this.missingTemplateNormalizedName = null; this.missingTemplateReason = null; this.missingTemplateCauseException = null; } private MaybeMissingTemplate(String normalizedName, MalformedTemplateNameException missingTemplateCauseException) { this.template = null; this.missingTemplateNormalizedName = normalizedName; this.missingTemplateReason = null; this.missingTemplateCauseException = missingTemplateCauseException; } private MaybeMissingTemplate(String normalizedName, String missingTemplateReason) { this.template = null; this.missingTemplateNormalizedName = normalizedName; this.missingTemplateReason = missingTemplateReason; this.missingTemplateCauseException = null; } public Template getTemplate() { return template; } public String getMissingTemplateReason() { return missingTemplateReason != null ? missingTemplateReason : (missingTemplateCauseException != null ? missingTemplateCauseException.getMalformednessDescription() : null); } public String getMissingTemplateNormalizedName() { return missingTemplateNormalizedName; } } }
作用:执行模板的缓存和按需加载。实际的模板“文件”加载被委托给一个TemplateLoader对象,你可以在构造函数中指定它。缓存的某些方面委托给CacheStorage对象,你也可以在构造函数中指定。
URLTemplateSource类
代码
class URLTemplateSource { private final URL url; private URLConnection conn; private InputStream inputStream; private Boolean useCaches; URLTemplateSource(URL url, Boolean useCaches) throws IOException { this.url = url; this.conn = url.openConnection(); this.useCaches = useCaches; if (useCaches != null) { conn.setUseCaches(useCaches.booleanValue()); } } @Override public boolean equals(Object o) { if (o instanceof URLTemplateSource) { return url.equals(((URLTemplateSource) o).url); } else { return false; } } @Override public int hashCode() { return url.hashCode(); } @Override public String toString() { return url.toString(); } long lastModified() { if (conn instanceof JarURLConnection) { URL jarURL = ((JarURLConnection) conn).getJarFileURL(); if (jarURL.getProtocol().equals("file")) { return new File(jarURL.getFile()).lastModified(); } else { // Use the URL mechanism URLConnection jarConn = null; try { jarConn = jarURL.openConnection(); return jarConn.getLastModified(); } catch (IOException e) { return -1; } finally { try { if (jarConn != null) jarConn.getInputStream().close(); } catch (IOException e) { } } } } else { long lastModified = conn.getLastModified(); if (lastModified == -1L && url.getProtocol().equals("file")) { return new File(url.getFile()).lastModified(); } else { return lastModified; } } } InputStream getInputStream() throws IOException { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { } this.conn = url.openConnection(); } inputStream = conn.getInputStream(); return inputStream; } void close() throws IOException { try { if (inputStream != null) { inputStream.close(); } else { conn.getInputStream().close(); } } finally { inputStream = null; conn = null; } } Boolean getUseCaches() { return useCaches; } void setUseCaches(boolean useCaches) { if (this.conn != null) { conn.setUseCaches(useCaches); this.useCaches = Boolean.valueOf(useCaches); } } }
作用:包装一个URL对象,并实现一个典型模板源所需的方法。
TemplateLookupStrategy类
代码
public abstract class TemplateLookupStrategy { public static final TemplateLookupStrategy DEFAULT_2_3_0 = new Default020300(); public abstract TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException; private static class Default020300 extends TemplateLookupStrategy { @Override public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException { return ctx.lookupWithLocalizedThenAcquisitionStrategy(ctx.getTemplateName(), ctx.getTemplateLocale()); } @Override public String toString() { return "TemplateLookupStrategy.DEFAULT_2_3_0"; } } }
作用:为请求模板的模板名找到TemplateLoader-level(存储级)模板源(如在Configuration.getTemplate(String)中)。这通常意味着尝试各种TemplateLoader对象级别的模板名称(也就是所谓的源名称;参见Template.getSourceName())是从请求的名称推导出来的。
TemplateLookupContext类
代码
public abstract class TemplateLookupContext { private final String templateName; private final Locale templateLocale; private final Object customLookupCondition; public abstract TemplateLookupResult lookupWithAcquisitionStrategy(String templateName) throws IOException; public abstract TemplateLookupResult lookupWithLocalizedThenAcquisitionStrategy(String templateName, Locale templateLocale) throws IOException; TemplateLookupContext(String templateName, Locale templateLocale, Object customLookupCondition) { this.templateName = templateName; this.templateLocale = templateLocale; this.customLookupCondition = customLookupCondition; } public String getTemplateName() { return templateName; } public Locale getTemplateLocale() { return templateLocale; } public Object getCustomLookupCondition() { return customLookupCondition; } public TemplateLookupResult createNegativeLookupResult() { return TemplateLookupResult.createNegativeResult(); } }
作用:用作TemplateLookupStrategy.lookup(TemplateLookupContext)的参数。不能创建它的实例,只能从FreeMarker接收它们。
TemplateLookupResult类
代码
public abstract class TemplateLookupResult { static TemplateLookupResult createNegativeResult() { return NegativeTemplateLookupResult.INSTANCE; } /** Used internally to create the appropriate kind of result from the parameters. */ static TemplateLookupResult from(String templateSourceName, Object templateSource) { return templateSource != null ? new PositiveTemplateLookupResult(templateSourceName, templateSource) : createNegativeResult(); } private TemplateLookupResult() { // nop } public abstract String getTemplateSourceName(); public abstract boolean isPositive(); abstract Object getTemplateSource(); private static final class PositiveTemplateLookupResult extends TemplateLookupResult { private final String templateSourceName; private final Object templateSource; private PositiveTemplateLookupResult(String templateSourceName, Object templateSource) { NullArgumentException.check("templateName", templateSourceName); NullArgumentException.check("templateSource", templateSource); if (templateSource instanceof TemplateLookupResult) { throw new IllegalArgumentException(); } this.templateSourceName = templateSourceName; this.templateSource = templateSource; } @Override public String getTemplateSourceName() { return templateSourceName; } @Override Object getTemplateSource() { return templateSource; } @Override public boolean isPositive() { return true; } } private static final class NegativeTemplateLookupResult extends TemplateLookupResult { private static final NegativeTemplateLookupResult INSTANCE = new NegativeTemplateLookupResult(); private NegativeTemplateLookupResult() { // nop } @Override public String getTemplateSourceName() { return null; } @Override Object getTemplateSource() { return null; } @Override public boolean isPositive() { return false; } } }
作用:TemplateLookupStrategy.lookup(TemplateLookupContext)和类似的查找方法的返回值,通常由TemplateLookupContext.lookupWithAcquisitionStrategy(String)或者TemplateLookupContext.createNegativeLookupResult()获取此类的对象,不能直接创建shi它的实例。
注:Freemarker代码来自FreeMarker 中文官方参考手册
新手写的代码分析,文章若有错误还请指出
这篇关于Freemarker源码分析(5)cache包中其他的类的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享