serialFilter
字段的类型就是ObjectInputFilter
,这个接口是一个函数接口(可以对方法进行赋值),其中定义的抽象方法是:
Status checkInput(FilterInfo filterInfo);
接受的参数类型FilterInfo
是内部的一个接口,封装了各种过滤的信息:
interface FilterInfo {
/**
* The class of an object being deserialized.
* For arrays, it is the array type.
* For example, the array class name of a 2 dimensional array of strings is
* "{@code [[Ljava.lang.String;}".
* To check the array's element type, iteratively use
* {@link Class#getComponentType() Class.getComponentType} while the result
* is an array and then check the class.
* The {@code serialClass is null} in the case where a new object is not being
* created and to give the filter a chance to check the depth, number of
* references to existing objects, and the stream size.
*
* @return class of an object being deserialized; may be null
*/
Class> serialClass();
/**
* The number of array elements when deserializing an array of the class.
*
* @return the non-negative number of array elements when deserializing
* an array of the class, otherwise -1
*/
long arrayLength();
/**
* The current depth.
* The depth starts at {@code 1} and increases for each nested object and
* decrements when each nested object returns.
*
* @return the current depth
*/
long depth();
/**
* The current number of object references.
*
* @return the non-negative current number of object references
*/
long references();
/**
* The current number of bytes consumed.
* @implSpec {@code streamBytes} is implementation specific
* and may not be directly related to the object in the stream
* that caused the callback.
*
* @return the non-negative current number of bytes consumed
*/
long streamBytes();
}
这个接口作为一个函数接口,更多的情况下是作为方法引用存在的,比如在RMI中的:
RegsitryImpl::registryFilter
在Config
类的静态代码块中会初始化其内部字段configuredFilter
,这个字段会被赋值给serialFilter
:
从代码上来看,首先会获取一个叫SERIAL_FILTER_PROPNAME
的常量(其值是jdk.serialFilter
),如果结果不为null的话就传入createFilter
方法:
public static ObjectInputFilter createFilter(String pattern) {
Objects.requireNonNull(pattern, "pattern");
return Global.createFilter(pattern, true);
}
这里又涉及到了Global (implements) ObjectInputFilter
这个类,根据官方注释,Global#createFilter
方法的作用就是把字符串解析成一个ObjectInputFilter
对象(Returns an ObjectInputFilter from a string of patterns),具体分析见后文的Global部分。
从方法名字就可以看出来,它们是serialFilter
字段的getter和setter方法。
public static ObjectInputFilter getSerialFilter() {
synchronized (serialFilterLock) {
return serialFilter;
}
}
public static void setSerialFilter(ObjectInputFilter filter) {
Objects.requireNonNull(filter, "filter");
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SerializablePermission("serialFilter"));
}
synchronized (serialFilterLock) {
if (serialFilter != null) {
throw new IllegalStateException("Serial filter can only be set once");
}
serialFilter = filter;
}
}
获取(初始化)一个ObjectInputStream
对象中的ObjectInputFilter
类型的字段(即serialFilter
)。
public static ObjectInputFilter getObjectInputFilter(ObjectInputStream inputStream) {
Objects.requireNonNull(inputStream, "inputStream");
return sun.misc.SharedSecrets.getJavaOISAccess().getObjectInputFilter(inputStream);
}
public static void setObjectInputFilter(ObjectInputStream inputStream,
ObjectInputFilter filter) {
Objects.requireNonNull(inputStream, "inputStream");
sun.misc.SharedSecrets.getJavaOISAccess().setObjectInputFilter(inputStream, filter);
}
Global
类是Config
内部的静态类,实现了ObjectInputFilter
接口,内部也有chekInput()
方法的实现,所以可以把Global
类的对象看作是一个过滤器,它可以直接赋值到ObjectInputStream.serialFilter
字段上。
在Global
类的内部有一个储存filter的列表:
private final List, Status>> filters;
在checkInput()
方法中会遍历这个列表来检测待反序列化的类:
public Status checkInput(FilterInfo filterInfo) {
...
Class> clazz = filterInfo.serialClass();
if (clazz != null) {
...
if (clazz.isPrimitive()) {
// Primitive types are undecided; let someone else decide
return Status.UNDECIDED;
} else {
// Find any filter that allowed or rejected the class
final Class> cl = clazz;
// 关键代码,用stream来遍历filter的list
Optional status = filters.stream()
.map(f -> f.apply(cl))
.filter(p -> p != Status.UNDECIDED)
.findFirst();
return status.orElse(Status.UNDECIDED);
}
}
return Status.UNDECIDED;
}
Global
的构造方法会根据传入的"String pattern"来创建不同的filter然后添加到上文中提到了存储filter的列表中(实际上列表中存储的是一个个Lambda表达式),官方称之为 ***"Pattern-Based Filters"***。
简单来说,这个String pattern就是一条一条的规则,规定着哪些类不可以被反序列化,哪些类可以被反序列化,这些规则如下(引自官方文档):
!
", the class is rejected if the rest of the pattern matches, otherwise it is accepted.**
" it matches any class in the package and all subpackages.*
" it matches any class in the package*
", it matches any class with the pattern as a prefix.接上文的Global#createrFilter
方法,这个方法就是传入一个规则,然后初始化了一个Global
对象:
static ObjectInputFilter createFilter(String pattern, boolean checkComponentType) {
Global filter = new Global(pattern, checkComponentType);
return filter.isEmpty() ? null : filter;
}
小结一下每个类的主要作用:
ObjectInputFilter
是filter要实现的接口,同时也是一个函数接口(意味着可以传入一个方法引用),其checkInput()
方法规定着反序列化check的具体实现。Config
类可以看作是一个“配置类”,规定着filter如何初始化,如何为一个ObjectInputStream
设置(获取)serialFilter
。Global
类是JEP290规则的具体实现,它可以把一个个的String pattern转化成相应的filter;同时这个类本身也可以作为filter存在。所以再回过头来看在Global
类的静态代码块中所提到的那个常量jdk.serialFilter
,这个常量其实就是一个属性名,Java会获取这个属性名(key)所对应的value,然后以这个value作为"String pattern",来创建一个filter(Global
对象)。
A process-wide filter is configured via a system property or a configuration file. The system property, if supplied, supersedes the security property value.
*System property jdk.serialFilter
*Security property jdk.serialFilter in conf/security/java.properties
两种过滤模式:
全局过滤是指,在ObjectInputStream
的创建过程中,通过ObjectInputFilter.Config
这个内部类来为serialFilter
赋值,进而所有ObjectInputStream
对象在创建的时候就完成了serialFilter
字段的初始化工作。
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
// 从Config中获取serialFilter的值
serialFilter = ObjectInputFilter.Config.getSerialFilter();
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
}
// ObjectInputFilter.Config#gerSerialFilter
public static ObjectInputFilter getSerialFilter() {
synchronized (serialFilterLock) {
return serialFilter;
}
}
局部过滤是指,在ObjectInputStream
的创建过程中不初始化serialFilter
字段,而是在需要的时候对单个ObjectInputStream
对象进行单独设置。
private final void setInternalObjectInputFilter(ObjectInputFilter filter) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SerializablePermission("serialFilter"));
}
// Allow replacement of the process-wide filter if not already set
if (serialFilter != null &&
serialFilter != ObjectInputFilter.Config.getSerialFilter()) {
throw new IllegalStateException("filter can not be set more than once");
}
if (totalObjectRefs > 0 && !Caches.SET_FILTER_AFTER_READ) {
throw new IllegalStateException(
"filter can not be set after an object has been read");
}
this.serialFilter = filter;
}