2025年某头部直播App突发线上事故——电商模块的订单消息竟出现在直播间礼物列表!经字节跳动技术团队溯源,发现全局LiveDataBus的Key命名冲突导致数据污染。
灾难现场:
源码定位(LiveDataBus.java):
public class LiveDataBus {
private final HashMap<String, MutableLiveData<Object>> eventMap = new HashMap<>();
public MutableLiveData<Object> with(String key) {
return eventMap.getOrDefault(key, new MutableLiveData<>());
}
} 污染原理:全局HashMap未做模块隔离,不同模块的同名Key共享同一LiveData实例
核心设计:
object ModuleLiveDataBus {
// 三级Key结构:模块名_子域_事件名
privateval busMap = ConcurrentHashMap<String, MutableLiveData<*>>()
funbuildKey(module: String, domain: String, event: String): String {
return"
${module}_$
{domain}_$event"
}
@Suppress("UNCHECKED_CAST")
fun<T>getChannel(module: String, domain: String, event: String): MutableLiveData<T> {
val key = buildKey(module, domain, event)
return busMap.getOrPut(key) { SafeMutableLiveData<T>() } as MutableLiveData<T>
}
} 实战效果:
污染现场:
源码魔改(LifecycleBoundObserver.java):
class AutoCleanObserverextendsLifecycleBoundObserver {
privatefinal WeakReference<Context> moduleContext;
@Override
publicvoidonStateChanged(@NonNull LifecycleOwner source, Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// 模块Context销毁时自动解除订阅
if (moduleContext.get() == null || moduleContext.get().isDestroyed()) {
liveData.removeObserver(this);
}
}
super.onStateChanged(source, event);
}
} 防御机制:
污染场景:
源码增强(SafeMutableLiveData.java):
public classSafeMutableLiveData<T> extendsMutableLiveData<T> {
privatefinalAtomicLongeventVersion=newAtomicLong(0);
privatefinal Map<Observer<? super T>, Long> observerVersions = newConcurrentHashMap<>();
@Override
publicvoidobserve(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, newObserver<T>() {
@Override
publicvoidonChanged(T t) {
longcurrentVersion= eventVersion.get();
if (observerVersions.getOrDefault(observer, -1L) < currentVersion) {
observer.onChanged(t);
observerVersions.put(observer, currentVersion);
}
}
});
}
@Override
publicvoidsetValue(T value) {
eventVersion.incrementAndGet();
super.setValue(value);
}
} 防御效果:
防御级方案:
// 基于APT的编译期隔离方案
@ModuleEvent(module = "user", domain = "profile")
publicclassUserProfileEvent {
@EventKey("update")
publicstaticfinal MutableLiveData<User> UPDATE = newSafeMutableLiveData<>();
}
// 编译后生成隔离代码
publicfinalclassUserProfileEventWrapper {
publicstatic MutableLiveData<User> getUpdateChannel() {
return ModuleLiveDataBus.getChannel("user", "profile", "update");
}
} 技术要点:
原子级防御:
inline fun <reified T> receiveEvent(key: String): LiveData<T> {
return liveDataBus.with(key).filter { it is T } as LiveData<T>
} 通过本文剖析,开发者应立即构建:
架构箴言: "模块如星河,消息似流星; 三重结界护,污染永归零!"