此文章的java环境:1.8.0_131
本人出于学习阶段,如有不正请指正
来自API的解释:描述给定 Java bean 激发的一组事件的 EventSetDescriptor。
给定的事件组都是作为方法调用在单个事件侦听器接口上传递的,事件侦听器对象可以通过调用事件源提供的注册方法进行注册
构造器:
EventSetDescriptor(Class<?> sourceClass, String eventSetName, Class<?> listenerType, String listenerMethodName)
来自API的解释:假定按照最简单的标准设计模式创建 EventSetDescriptor,其中指定事件 “fred” 是 :
(1) 作为接口 FredListener 的单个方法上的调用传递的;
(2) 它有一个 FredEvent 类型的参数;
(3) 其中 FredListener 可以通过调用源组件的 addFredListener 方法注册,并通过调用 removeFredListener 方法移除。
注意:在方法中首先调用了第三个构造器,只不过后三个参数分别构造为:
add/remove/get+getListenerClassName(listenerType)
看下这个getListenerClassName方法的代码:
private static String getListenerClassName(Class<?> cls) {
String className = cls.getName();
return className.substring(className.lastIndexOf('.') + 1);
}
简而言之,这个地方就是取类的真正的名字,例如:welcome.helloworld -> helloworld
接着调用了如下代码,进行了check-throw的一个过程:
String eventName = NameGenerator.capitalize(eventSetName) + "Event";
Method[] listenerMethods = getListenerMethods();
if (listenerMethods.length > 0) {
Class[] args = getParameterTypes(getClass0(), listenerMethods[0]);
// 检查EventSet,大体的流程是先获取到Listener Methods,最后获取到目前的参数类型(目前没有搞懂为什么获取到的类型是有序的,而且取的是第一个),最后判断第一个方法名是不是eventName,不是则抛出异常
if (!"vetoableChange".equals(eventSetName) && !args[0].getName().endsWith(eventName)) {
throw new IntrospectionException("Method \"" + listenerMethodName +
"\" should have argument \"" +
eventName + "\"");
}
}
第二个构造器:
public EventSetDescriptor(Class<?> sourceClass,
String eventSetName,
Class<?> listenerType,
String listenerMethodNames[],
String addListenerMethodName,
String removeListenerMethodName)
throws IntrospectionException {
this(sourceClass, eventSetName, listenerType, listenerMethodNames, addListenerMethodName, removeListenerMethodName, null);
}
直接调用第三个构造器,没什么好说的
第三个构造器
public EventSetDescriptor(Class<?> sourceClass,String eventSetName,Class<?> listenerType,String listenerMethodNames[],String addListenerMethodName,String removeListenerMethodName,String getListenerMethodName) throws IntrospectionException {
if (sourceClass == null || eventSetName == null || listenerType == null) {
// 非空判断
throw new NullPointerException();
}
//将部分参数注入,其他部分方法调用的源头来自此处
setName(eventSetName);
setClass0(sourceClass);
setListenerType(listenerType);
Method[] listenerMethods = new Method[listenerMethodNames.length];
for (int i = 0; i < listenerMethodNames.length; i++) {
// 对参数名进行非空判断
if (listenerMethodNames[i] == null) {
throw new NullPointerException();
}
//依次将listenerType类的名为listenerMethodNames[i],且只有一个参数的方法放入数组
listenerMethods[i] = getMethod(listenerType, listenerMethodNames[i], 1);
}
setListenerMethods(listenerMethods);
setAddListenerMethod(getMethod(sourceClass, addListenerMethodName, 1));
setRemoveListenerMethod(getMethod(sourceClass, removeListenerMethodName, 1));
// 没有找到getListener也能处理.
Method method = Introspector.findMethod(sourceClass, getListenerMethodName, 0);
if (method != null) {
setGetListenerMethod(method);
}
}
private void setListenerMethods(Method[] methods) {
if (methods == null) {
return;
}
if (listenerMethodDescriptors == null) {
listenerMethodDescriptors = new MethodDescriptor[methods.length];
for (int i = 0; i < methods.length; i++) {
listenerMethodDescriptors[i] = new MethodDescriptor(methods[i]);
}
}
this.listenerMethodsRef = getSoftReference(methods);
}
setListenerMethods这个方法第一次调用是在构造器,所以可以理解为listenerMethodDescriptors 会在构造方法时被调用,而listenerMethodDescriptors会在第一次调用setListenerMethods这个方法时,且参数不为空时会被设置,设置成功后若再次调用次方法,则会给listenerMethodsRef赋一个软引用数组。
在这里补充下软引用的知识:
非必须引用,内存溢出之前进行回收。软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。
在构造器中,调用了如下getMethod方法,这个方法也大概的讲下:
private static Method getMethod(Class<?> cls, String name, int args)
throws IntrospectionException {
if (name == null) {
return null;
}
Method method = Introspector.findMethod(cls, name, args);
if ((method == null) || Modifier.isStatic(method.getModifiers()))
{
throw new IntrospectionException("Method not found: " + name + " on class " + cls.getName());
}
return method;
}
当前方法只会获取cls类中名字为name,且参数个数为args的非静态方法(如果是静态方法,则会被报错)。这种方法在我们自己的代码当中也可用于实现类似一些框架的自动寻找get/set方法的一个模板。
public Class<?> getListenerType() {
return (this.listenerTypeRef != null)
? this.listenerTypeRef.get()
: null;
}
private void setListenerType(Class<?> cls) {
this.listenerTypeRef = getWeakReference(cls);
}
这一对方法也是利用了弱引用,补充下弱引用的知识:当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。
getListenerMethods方法:
public synchronized Method[] getListenerMethods() {
Method[] methods = getListenerMethods0();
if (methods == null) {
if (listenerMethodDescriptors != null) {
methods = new Method[listenerMethodDescriptors.length];
for (int i = 0; i < methods.length; i++) {
methods[i] = listenerMethodDescriptors[i].getMethod();
}
}
setListenerMethods(methods);
}
return methods;
}
当前方法时获取目标监听器的接口, getListenerMethods0方法获取的是关于listenerMethodsRef的软引用。
当软引用失效的时候,会从listenerMethodsRef来获取方法,在获取成功后会将获取到的返回值(数组)重新创建软引用并重新赋值给listenerMethodsRef
在类中还有两个private的构造器,是用于合并两个EventSetDescriptor,没有值得深究的代码