2021SC@SDUSC
FreeMarker代码分析第七篇
util包
IdentityHashMap.java
代码分析
package freemarker.ext.util;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Was used instead of {@link java.util.IdentityHashMap} before that was added to Java itself in Java 1.4.
*
* @deprecated Use {@link java.util.IdentityHashMap} instead.
*/
@SuppressWarnings("rawtypes")
@Deprecated
public class IdentityHashMap
extends AbstractMap
implements Map, Cloneable, java.io.Serializable {
public static final long serialVersionUID = 362498820763181265L;
/**
* 存储哈希表数据
*/
private transient Entry table[];
/**
* 用于保存哈希表中mapping的数量
*/
private transient int count;
ModelCache.java
代码分析
package freemarker.ext.util;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.IdentityHashMap;
import java.util.Map;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelAdapter;
/**
* 此类被各种包装用来用于实现模型的内部缓存
*/
public abstract class ModelCache {
private boolean useCache = false;
private Map<Object, ModelReference> modelCache = null;
private ReferenceQueue<TemplateModel> refQueue = null;
protected ModelCache() {
}
/**
* Sets whether this wrapper caches model instances. Default is false.
* When set to true, calling {@link #getInstance(Object)}
* multiple times for the same object will return the same model.
*/
public synchronized void setUseCache(boolean useCache) {
this.useCache = useCache;
if (useCache) {
modelCache = new IdentityHashMap<>();
refQueue = new ReferenceQueue<>();
} else {
modelCache = null;
refQueue = null;
}
}
/**
* @since 2.3.21
*/
public synchronized boolean getUseCache() {
return useCache;
}
public TemplateModel getInstance(Object object) {
if (object instanceof TemplateModel) {
return (TemplateModel) object;
}
if (object instanceof TemplateModelAdapter) {
return ((TemplateModelAdapter) object).getTemplateModel();
}
if (useCache && isCacheable(object)) {
TemplateModel model = lookup(object);
if (model == null) {
model = create(object);
register(model, object);
}
return model;
} else {
return create(object);
}
}
protected abstract TemplateModel create(Object object);
protected abstract boolean isCacheable(Object object);
public void clearCache() {
if (modelCache != null) {
synchronized (modelCache) {
modelCache.clear();
}
}
}
private final TemplateModel lookup(Object object) {
ModelReference ref = null;
// NOTE: we're doing minimal synchronizations -- which can lead to
// duplicate wrapper creation. However, this has no harmful side-effects and
// is a lesser performance hit.
synchronized (modelCache) {
ref = modelCache.get(object);
}
if (ref != null)
return ref.getModel();
return null;
}
private final void register(TemplateModel model, Object object) {
synchronized (modelCache) {
// Remove cleared references
for (; ; ) {
ModelReference queuedRef = (ModelReference) refQueue.poll();
if (queuedRef == null) {
break;
}
modelCache.remove(queuedRef.object);
}
// Register new reference
modelCache.put(object, new ModelReference(model, object, refQueue));
}
}
/*
在模型缓存中注册的特殊软参考。
当它被清除 (即模型变得遥不可及) 时,
它会从模型缓存中删除自己
*/
private static final class ModelReference extends SoftReference<TemplateModel> {
Object object;
ModelReference(TemplateModel ref, Object object, ReferenceQueue<TemplateModel> refQueue) {
super(ref, refQueue);
this.object = object;
}
TemplateModel getModel() {
return this.get();
}
}
}
ModelFactory.java
代码分析
package freemarker.ext.util;
import freemarker.template.ObjectWrapper;
import freemarker.template.TemplateModel;
/*
用于创建在 {@link ModelCache}中的不同包装模型的接口
*/
public interface ModelFactory {
/*
为属于特殊包装的对象创建包装模型
*/
TemplateModel create(Object object, ObjectWrapper wrapper);
}
WrapperTemplateModel.java
代码分析
package freemarker.ext.util;
import freemarker.template.TemplateModel;
/*
模板模型的通用界面,用于包装一些底层对象,
并希望提供对该包裹对象的访问权限。
*/
public interface WrapperTemplateModel extends TemplateModel {
/*
检索此模型包裹的原始对象。
*/
public Object getWrappedObject();
}