SubscriberMethodFinder類
SubscriberMethodFinder
大體就是去注冊后對應的方法
其中,屬性
private static final int BRIDGE = 0x40;
有對應的說明:
In newer class files, compilers may add methods. Those are called bridge or synthetic methods.
EventBus must ignore both. There modifiers are not public but defined in the Java class file format:
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1
自己也沒有研究過jvm,簡單貼一下圖
下面對應的變量修飾符
private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
也就是,
方法上的注解,會忽略這幾種修飾符的方法
屬性方面
先重點看一下這2個容器
一個是 : 本類存儲的容器類,用于 查找 和 存儲
另一個是 :傳入的引用
方法大體了解
這里,我們可以發現,
除了 構造 和 findSubscriberMethods方法 是 public對外的
其他,都是 private 的
也就是,我們主要認識 findSubscriberMethods方法 即可
和EventBus 2.4 對比
我們大體可以猜測,其他多余出來的方法,都是用于判斷反射的
findSubscriberMethods方法
先一起大體過一下
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
這里,大體就是
- 如果有Map緩存中有值,就直接獲取
- 如果 ignoreGeneratedIndex為true 就 findUsingReflection(subscriberClass) 通過反射獲取
- 如果 ignoreGeneratedIndex為false ,就 findUsingInfo(subscriberClass) 獲取
- 最后
- subscriberMethods 為空,內部報異常(對外是不會提示的)
- subscriberMethods 不空,把對應的key為 subscriberClass, value為subscriberMethods 加入到 Map緩存中
findUsingInfo方法
上面提到的
如果Map緩存中 沒有值,并且 ignoreGeneratedIndex為false的時候
會調用這個方法
具體看下源碼
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
這里通過 prepareFindState(), 獲取 FindState 對象
(具體方法,見下面的方法說明)
FindState 靜態內部類
這里因為上面的方法會獲取這個對象
所以,我們先來看一下這個對象
static class FindState {
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class<?> methodClass = method.getDeclaringClass();
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
這個代碼比較長,我們大體看一下即可
- initForSubscriber方法
- 初始化靜態內部類
- 傳遞 Class<?> 對象
- 設置 SubscriberInfo 為空
- recycle方法
- 所有集合都 clear , 引用對象都設置為null
- 因為是靜態的, 所以 回收后再次調用
- checkAdd方法
- boolean類型
- 將對應的 key 為 eventType, value 為 Method 放入到 Map中
- 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
- Usually a subscriber doesn't have methods listening to the same event type.
- 這里有2次check, 第一次check是比較快, 第二次會再次check,通常一個subscriber不會監聽2個相同的event
- checkAddWithMethodSignature方法
- 也就是第二次check,通過拼接一個string來作為一個key
- moveToSuperclass方法
- 如果 skipSuperClasses為true,或者 Superclass的startsWith對應的時候,設置 clazz = null
- 其他時候,返回 clazz = clazz.getSuperclass().getName()
大體就是
- 初始化對應的類屬性
- 再就是check是否已經add過了(這里是2次check)
- 把class的屬性,設置為Super的class(特殊情況設置為null)
prepareFindState方法
這里是前面 findUsingInfo方法 中用到的
也就是用來獲取FindState對象的方法
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
這里,知道這里有一個 FIND_STATE_POOL 對象池
對象個數 POOL_SIZE 為 4
具體對象為 FindState
是一個 靜態內部類
for循環取值:
- 如果不為空, 則找到對象池中 一個不為空的對象
- 如果為空,就返回一個新的 FindState對象()
getMethodsAndRelease 方法
先看一下源碼
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
這里大體就是獲取 FindState中的List<SubscriberMethod>類型的對象subscriberMethods
將對應的FindState對象放入對象池中
最后返回List<SubscriberMethod>的值
getSubscriberInfo方法
也先看一下源碼
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
也就是如果傳入的findState對象不空,并且有SubscriberInfo的值
(這塊自己感覺沒有賦值的地方,應該為null,具體先不糾結)
或者對應的值,并且SubscriberInfo不為空,Class相同的時候,
返回對應的SubscriberInfo對象
如果上面不符合,會取從構造傳進來的subscriberInfoIndexes對象中
for循環,獲取第一個 SubscriberInfo 對象
findUsingReflection方法
這里就不貼代碼了
大體為:
- 先通過 prepareFindState方法,獲得內部靜態類的FindState對象
- 再while (findState.clazz != null)循環
- 通過findUsingReflectionInSingleClass方法
- 每次獲取一個類后,通過 FindState的moveToSuperclass()方法,設置class引用
- 如果有父類,設置為class=class.getSuperclass()
- 如果沒有父類,賦值class=null,從而讓findUsingReflection中,離開while循環
findUsingReflectionInSingleClass方法
上面用到的
大體為:
- 獲取每個SingleClass的方法,
- 在除去其他修飾的方法后,獲取 注解的 Subscribe對象,
- 放入FindState對象的subscriberMethods容器中
簡單總結
對外,就2個方法
- 一個是構造,傳入 List<SubscriberInfoIndex> subscriberInfoIndexes 等變量
- 一個是 findSubscriberMethods, 去找對應的注冊者Subscriber的方法
對應的方法,會存入
Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>()
容器中
- 如果容器中有,會從容器中獲取 List<SubscriberMethod>
- 如果容器中沒有
- ignoreGeneratedIndex 為 true,則通過反射去拿具體的類中獲取
- ignoreGeneratedIndex 為 false,則 通過 findUsingInfo方法獲取
- FindState對象池中,獲取對象
- 通過while循環(這里后面的方法會設置對象,確定可以跳出循環)
- 遍歷,獲取 List<SubscriberMethod> 對象
- 如果FindState 對象池 中有,則直接獲取
- 如果 FindState 對象池中沒有,則 從構造傳入的subscriberInfoIndexes對象中獲取
- 其實,最終也就獲取 List<SubscriberMethod>
- 通過傳進來的Class<?> 對象
- 也就是在 Activity或者Fragment中注冊的Class
- 獲取@Subscriber 進行注解的方法 們
(其實,自己不太理解,這里為什么用一個容器存儲,為什么要這樣寫結構 等等,只是簡單的敘述了下流程,等有時間,再考慮一下)