因为我对Handler的了解,居然直接给我加了5K?!

本文围绕Android的Handler展开,介绍其是线程切换工具类,可实现子线程到主线程的UI刷新。还探讨了线程中Handler和Looper的数量、主线程与子线程使用Handler的区别、内存泄漏原因、消息阻塞实现等,同时提及优化机制和线程安全保证等内容。

1 Handler是什么?

android提供的线程切换工具类。主要的作用是通过handler实现从子线程切换回主线程进行ui刷新操作。

1.1 为什么Handler能实现线程切换?

在创建Handler的时候需要传入目标线程的Looper。(没有传入Looper默认拿当前线程的Looper,如果当前线程也没有准备好Looper会抛异常)
而当sendMessage的时候,会将当前的Handler对象赋值给Message中的target变量。并将该Message存到传入目标线程Looper的MessageQueue中
当Looper消费Message的时候便会拿到Message中的taeget执行dispatchMessage(msg)方法,从而实现线程切换。

第一次看我文章的小伙伴可以关注下我,不定期分享Android相关资料,Android热点实时分享、Android新鲜事第一时间知道。

1.2 为什么主线程才能刷新ui,子线程不可以?

‘android的ui刷新并不是线程安全的’ 所以必须要有一个线程专门来做这件事情,那就是主线程。
刷新ui的时候会检查当前线程是否为主线程,如果不是会抛异常。

view在更新的时候由于可能会发生大小、位置等变化,会执行requestLayout来告诉父View自己要更新layout。
然后父View也会一层层调用requestLayout,最终去到ViewRootImpl#requestLayout,在其requestLayout中
会进行线程检查。

//ViewRootImpl#requestLayout
@Override
public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

//ViewRootImpl#checkThread
void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}

严格来说,子线程也不是不可以刷新ui。ndroid要设计成只有在主线程才能刷新ui?

设计成单线程刷新,目的是提高稳定性以及提高性能。 ①提高稳定性:由于多线程存在资源共享的问题一旦处理不妥当,会造成数据丢失、重复以及错乱等问题。单线程能有效降低出错风险,提高稳定性。
②从①中引申出,如果要处理好多线程的资源共享的问题,就需要增加同步锁、原子类、线程安全的集合等。这样必然会存在等待,而且由于ui刷新是非常
频繁的,如果出现大量而又频繁的等待,会增加cpu的负担,从而导致性能下降。

我这里也同大佬整理Android中高级相关的面试题分享给大家、View、Handler、Binder、Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料,如果你有需要的话,也可以私信我【进阶】获取

2 一个线程有几个Handler?

可以创建无数个,但是其内部的Looper只会有一个。

2.1 一个线程有几个Looper?如何保证?

一个线程只有一个Looper;
Looper内部是通过ThreadLocal保证的线程唯一,在Looper.prepare方法的时候创建并set进ThreadLocal。

2.2 为什么ThreadLocal能保证Looper线程唯一?

因为线程维护了一个ThreadLocalMap的容器,该容器专门提供给ThreadLocal获取数据。
key就是ThreadLocal,value就是需要获取的数据。

ThreadLocal设计思想 ① Thread 内部持有一个全局变量ThreadLocalMap<ThreadLocal(弱引用), T (强引用)> threadLocals
② ThreadLocal内部
get() -> 获取当前thread对象 -> 获取threadLocals(并且判空,为空就为该thread创建threadLocals)-> map.get(this) 获取到value
set(T value) -> 获取当前thread对象 -> 获取threadLocals(并且判空,为空就为该thread创建threadLocals)-> map.set(this, value)
remove() -> 获取当前thread对象 -> 获取threadLocals -> map.remove(this)

3 为什么主线程可以new Handler?

主线程: ActivityThread main方法已经帮我们准备好Looper了。 Looper.prepareMainLooper() Looper.loop() 这个是死循环,是主线程一直存活的关键。
所以在主线程可以直接new Handler,而且还可以不用穿Looper参数。(没有传入Looper默认拿当前线程的Looper,如果当前线程也没有准备好Looper会抛异常)

3.1 那么子线程中如何使用Handler?

**Looper.prepare()**准备Looper **Looper.loop()**让Looper运行起来 Looper.myLooper() 提供给Handler获得该线程的Looper
由于子线程的Looper创建是在prepare()中,无法保证外部的Hander立即能获得有效的Looper,所以需要做同步锁操作。

HandlerThread 封装好了一切同步操作,也可以用它。

3.2 子线程维持的Looper,无消息应该怎么处理?

由于Looper.loop()的存在会一直阻塞线程,线程是不会退出的,可能会导致内存泄漏。
需要手动退出 Looper.quit() -> MessageQueue quit()
MessageQueue quit()工作:清空所有Message,nativeWake唤醒等待,next()继续执行,dispose()

3.3 为什么主线程的Looper不需要退出?

如果主线程Looper退出了,整个程序就会退出了。因为整个app程序都是依靠Looper来分发处理消息,处理生命周期回调的。

4 Handler内存泄漏的原因是什么?

匿名内部类默认会持有外部类的引用。 内存泄漏:程序在向系统申请分配内存空间后(new),在使用完毕后未释放。内存泄漏容易造成OOM(内存溢出)。 OOM:我想要使用一个4M的连续空间,但是找不到。系统就会抛出OOM。

MessageQueue维护着所有将要处理的Message,在enqueueMessage的时候,将Handler对象存入Message target变量中。
所有Message的生命有可能会比Handler所在的Activity生命要长,Activity销毁了,但是Message都还没执行的话,该Activity
就无法销毁,导致内存泄漏。

5 Handler的消息阻塞是怎么实现的?

Handler的实现原理是使用了linux的两个系统调用实现的:eventfd + epoll eventfd负责通知 epoll 负责监听
首先会通过eventfd系统调用创建一个唤醒fd并且注册到epoll里边。
如果当有延时消息入队的时候,会根据消息的延时时长为epoll设置阻塞时长,知道超时epoll自动唤醒,然后返回java层处理消息
如果当有立即执行的消息入队的时候,会通过写入数据到唤醒fd从而唤醒epoll,然后返回java层处理消息
如果没有消息,epoll会一直阻塞,直到被唤醒。

5.1 Looper.loop()会阻塞主线程但为什么不会出现ANR?

ANR:应用无响应异常 ANR产生原因:当前的事件没有机会得到处理 例如:当前在处理一个点击事件,但是这个点击事件里边的处理是耗时的,主线程就会等待这个耗时的处理。
与此同时另外一个点击事件发送过来了,新的事件就会被阻塞。当事件超过某一个时间限制(触摸事件一般是5s)
仍未被执行,就会抛ANR。

所以ANR与Looper.loop()的阻塞是不相关的。并且Looper.loop()的阻塞是为了保证主线程不退出而设计的。

6 Handler如果让Message尽快执行执行?

发送异步消息。 方法:使用Message#setAsynchronous设置

这样还是不能实现尽快执行的,还需要增加同步屏障(一种特殊的消息)
但是添加以及移除同步屏障的方法,对开发者是不公开的。所以需要使用反射去设置。
记住:使用完之后必须要移除同步屏障,不然同步屏障后面的所有同步消息都无法执行的。
同步屏障的作用:拦截同步屏障后面所有同步消息,只允许异步消息用过。

使用场景介绍:ViewRoomtImpl中为了让消息尽快执行大量使用了异步消息

//ViewRoomtImpl#scheduleTraversals
void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); //添加消息屏障
            ...
        }
    }

//ViewRoomtImpl#unscheduleTraversals
    void unscheduleTraversals() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); //移除消息屏障
            ...
        }
    }

7 Handler有没有一些机制是有助于程序优化的?

IdleHandler:可以在程序空闲的时候,做一些不太耗时的操作。 使用方法
mHandler.getLooper().getQueue().addIdleHandler
mHandler.getLooper().getQueue().removeIdleHandler

IdleHandler#queueIdle(): 返回值用于告诉MessageQueue true:每次进入阻塞都会调用该IdleHandler,直到该IdleHandler被移除。 false:只调用一次IdleHandler,就被自动移除了。

使用场景: 1、Activity启动优化,onCreate,onStart,onResume中耗时较短但非必要的代码可以放到IdleHandler中执行,减少启动时间。
2、想要一个View绘制完成之后添加其他依赖于这个View的View,当然这个View#post()也能实现,区别就是前者会在消息队列空闲时执行。

8 MessageQueue如何保证线程安全?

MessageQueue内部的很多方法为了保证线程安全,都增加了对象锁synchronized (this)。

9 Message怎么创建?

Message.obtain():使用复用池,减少new Message,防止频繁GC。(频繁GC会导致内存抖动(STW) -> 导致卡顿)
设计模式:享元模式(类似例子 recycleview bindView createView)

最后

在这样,我也分享一份大佬收录整理的**View、Handler、Binder、Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料**

image.png

这些都是我现在闲暇还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效的帮助大家掌握知识、理解原理。

你也可以拿去查漏补缺,提升自身的竞争力。

如果你有需要的话,也可以私信我【进阶】获取

喜欢本文的话,不妨顺手给我点个赞、评论区留言或者转发支持一下呗~

public enum CompressionType { /** * deflater */ DEFLATER } /** * 分发策略,取值范围为:default、roundRobin、roundRobinWithKey roundRobin:实现负载均衡 的分发策略; default:实现随机的分发策略 * roundRobinWithKey:自定义的分发算法(实现负载均衡以及实现根据key的Hash值取余发送消息) * * @author ludingyang * @version 1.0 * @since 2021/1/26 */ public enum DispatchMode { DEFAULT, ROUND_ROBIN, ROUND_ROBIN_WITH_KEY } @Data @NoArgsConstructor @AllArgsConstructor public class EventCenterSendResult { private String topic; private String key; private Event sendEvent; private long timestamp; private Integer partition; } /** * 发送结果的封装类 * * @author ludingyang * @version 1.0 * @since 2021/3/17 */ @Data @NoArgsConstructor @AllArgsConstructor public class GenericEventCenterSendResult<T> { private String topic; private String key; private T sendEvent; private long timestamp; private Integer partition; } /** * Kafka迁移集群类型枚举 * * @author Zhou Wenpei * @version 1.0 * @since 2023/6/2 */ public enum KafkaClusterEnum { /** * 默认的主Kafka集群 */ PRIMARY(0, "primary"), /** * 迁移后的新Kafka集群 */ SECONDARY(1, "secondary"); @Getter private final String value; @Getter private final Integer type; (2); private static final Map<String, KafkaClusterEnum> VALUE_MAP = new HashMap<> KafkaClusterEnum(Integer type, String value) { this.value = value; this.type = type; } public static KafkaClusterEnum resolve(String value) { return VALUE_MAP.get(value); } static { for (KafkaClusterEnum type : values()) { VALUE_MAP.put(type.getValue(), type); } } } /** * kafka迁移操作枚举 * * @author Zhou Wenpei * @version 1.0 * @since 2023/6/13 */ public enum KafkaMigrationOperationEnum { /** * 切换生产者 */ REPLACE(0, "replace"), /** * 关闭生产者 */ CLOSE_PRODUCER(1, "closeProducer"), /** * 关闭消费者 */ CLOSE_CONSUMER(2, "closeConsumer"); @Getter private final String value; @Getter private final Integer type; private static final Map<String, KafkaMigrationOperationEnum> VALUE_MAP = new HashMap<>(2); KafkaMigrationOperationEnum(Integer type, String value) { this.value = value; this.type = type; } public static KafkaMigrationOperationEnum resolve(String value) { return VALUE_MAP.get(value); } static { for (KafkaMigrationOperationEnum type : values()) { VALUE_MAP.put(type.getValue(), type); } } } public class LogAccess { private LogAccess() { } public final static LogAccessor LOGGER = new LogAccessor(LogFactory.getLog(Handler.class)); } /** * 分区分配策略的枚举类 * * @author ludingyang * @version 1.0 * @since 2021/1/26 */ public enum PartitionAssignorMode { /** * CooperativeSticky和Sticky的结果是一样的,区别在于使用的算法不一样. CooperativeSticky是将Sticky一次重平衡的过程分割成多次过程。避免重平衡过长导致系统宕机或者影 响消息消费。 */ COOPERATIVE_STICKY, /** * 从字面意义上看, Sticky 是 “ 粘性的 ” ,可以理解为分配结果是带 “ 粘性的 ” : 1. 分区 的分配尽量的均衡 2. 每一次重分配的结果尽量与上一次分配结果保持一致 * 当这两个目标发生冲突时,优先保证第一个目标。第一个目标是每个分配算法都尽量尝试去完成的, 而第二个目标才真正体现出StickyAssignor 特性的。 */ STICKY, /** * Kafka 默认采用 RangeAssignor 的分配算法 。 RangeAssignor 对每个 Topic 进行独立的 分区分配。对于每一个 Topic ,首先对分区按照分区 ID 进行数值排序,然后订阅这个Topic * 的消费组的消费者再进行字典排序,之后尽量均衡的将分区分配给消费者。 这里只能是尽量均衡, 因为分区数可能无法被消费者数量整除,那么有一些消费者就会多分配到一些分区. */ RANGE, /** * RoundRobinAssignor 的分配策略是将消费组内订阅的所有 Topic 的分区及所有消费者进行排 序后尽量均衡的分配(RangeAssignor 是针对单个 Topic 的分区进行排序分配的)。 如果消费组内, * 消费者订阅的Topic列表是相同的 (每个消费者都订阅了相同的 Topic ),那么分配结果是尽量 均衡的(消费者之间分配到的分区数的差值不会超过1 )。 如果订阅的Topic列表是不同的 ,那么分配结果 是不保证 “ 尽量均衡” * 的 */ ROUND_ROBIN } /** * 序列化方式枚举类 * * @author Zhou Wenpei * @version 1.0 * @since 2023/9/12 */ @Getter public enum SerializeEnum { /** * Kryo 序列化,使用KryoSerializeUtil */ KRYO(0, "Kryo"), /** * Json序列化,使用JsonUtils */ JSON(1, "Json"); private final Integer type; private final String name; private static final Map<Integer, SerializeEnum> TYPE_MAP = new HashMap<> (2); static { for (SerializeEnum type : values()) { TYPE_MAP.put(type.getType(), type); } } public static SerializeEnum resolve(Integer type) { SerializeEnum serializeEnum = TYPE_MAP.get(type); if (Objects.isNull(serializeEnum)) { return JSON; } return serializeEnum; } SerializeEnum(Integer type, String name) { this.type = type; this.name = name; } } /** * 获取熔断器状态 * * @author Zhou Wenpei * @version 1.0 * @since 2023/5/17 */ public interface CircuitBreakerStatusService { /** * 获取对应主题的熔断器状态 * * @param topicName 主题名,即熔断器名 * @return 状态String */ String getCircuitBreakerStatus(String topicName); } public interface KafkaMigrationService { /** * 切换kafka集群 * @param kafkaMigrationType 切换到新的kafka集群类型 * @return true if success, false otherwise */ boolean changeKafkaTemplate(String kafkaMigrationType); /** * 关闭kafka生产者 * @param kafkaMigrationType 待关闭kafka生产者集群类型 */ void closeProducerService(String kafkaMigrationType); /** * 关闭kafka消费者 * @param kafkaMigrationType 待关闭kafka消费者集群类型 */ void closeConsumerService(String kafkaMigrationType); } public class AbstractAggregateDomainEvent<A> extends AbstractDomainEvent implements AggregateDomainEvent { private A source; public AbstractAggregateDomainEvent(String type) { super(type); } @Override public A source() { return source; } } @SuperBuilder @ToString public abstract class AbstractDomainEvent implements DomainEvent { protected String id = StringUtils.generateUUID(); protected Date createTime = new Date(); protected String type; public AbstractDomainEvent() { } public AbstractDomainEvent(String type) { this.type = type; } @Override public String id() { return id; } @Override public Date occurredOn() { return createTime; } @Override public String type() { return type; } protected String getClassName() { return this.getClass().getName(); } } public interface AggregateDomainEvent<A> extends DomainEvent { /** * 事件发生源 只针对由聚合产生的事件 */ A source(); default A getSource() { return source(); } } public interface DomainEvent { /** * 事件唯一标识 */ String id(); /** * 发生时间 */ Date occurredOn(); String type(); } /** * 扩展自 DomainEventPublisher 和 DomainEventHandlerRegistry 用于发布和管理领域事件处 理器 * * @author Fang Jiahao <fangjiahao@tp-link.com.cn> * @since 2020/6/8 */ public interface DomainEventBus extends DomainEventPublisher, DomainEventHandlerRegistry { } /** * 用于执行领域事件处理器 * * @author Fang Jiahao <fangjiahao@tp-link.com.cn> * @since 2020/6/8 */ @Getter @AllArgsConstructor public class DomainEventExecutor { private DomainEventSubscriber subscriber; private Executor executor; @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } DomainEventExecutor that = (DomainEventExecutor) o; return subscriber.equals(that.subscriber); } @Override public int hashCode() { return Objects.hash(subscriber); } public DomainEventExecutor(DomainEventSubscriber subscriber) { this.subscriber = subscriber; } } /** * 用于处理领域事件 * * @author Fang Jiahao <fangjiahao@tp-link.com.cn> * @since 2020/6/8 */ public interface DomainEventHandler<D> { } void handleEvent(final D aDomainEvent); /** * 用于注册 DomainEventHandler * * @author Fang Jiahao <fangjiahao@tp-link.com.cn> * @since 2020/6/8 */ public interface DomainEventHandlerRegistry { /** * 废弃的异步注册方法 * * @param dClass dClass * @param subscriber 注册类 * @deprecated use {@link # register(Class<D> dClass, DomainEventSubscriber<D> subscriber, ExecutorService * executorService)} instead. */ @Deprecated <D> void register(Class<D> dClass, DomainEventSubscriber<D> subscriber); /** * 同步调用注册接口 * * @param dClass dClass * @param subscriber 注册类 * @param <D> 类 */ <D> void registerSync(Class<D> dClass, DomainEventSubscriber<D> subscriber); /** * 异步调用注册接口 * * @param dClass * @param subscriber * @param <D> dClass 注册类 类 * @param executorService 业务线程池 */ <D> void register(Class<D> dClass, DomainEventSubscriber<D> subscriber, ExecutorService executorService); <D> void unRegister(DomainEventSubscriber<D> subscriber); } /** * 回调函数 * * @author Sun Xiaoyu * @version 1.0 * @since 2020-07-07 */ public interface DomainEventPostHandler<D extends DomainEvent> { void postEventSuccess(); } void postEventFailed(); /** * 用于发布领域事件 * * @author Fang Jiahao <fangjiahao@tp-link.com.cn> * @since 2020/6/8 */ public interface DomainEventPublisher { void publish(DomainEvent domainEvent); void publishSync(DomainEvent domainEvent); default void publishAll(List<DomainEvent> domainEvents) { for (DomainEvent aDomainEvent : domainEvents) { publish(aDomainEvent); } } } /** * 用于判断是否接受领域事件 处理领域事件 * * @author Fang Jiahao <fangjiahao@tp-link.com.cn> * @since 2020/6/4 */ public interface DomainEventSubscriber<D> { default boolean accept(D event) { return true; } void handleEvent(final D event); default void onEventFailed(D event) { } } } default void onEventSuccess(D event) { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface HandleEvent { } Class<? extends DomainEvent>[] value(); public class DuplicateGroupIdException extends RuntimeException { public DuplicateGroupIdException() { super(); } public DuplicateGroupIdException(String message) { super(message); } } public DuplicateGroupIdException(String message, Throwable cause) { super(message, cause); } public DuplicateGroupIdException(Throwable cause) { super(cause); } public class JsonUtils { /** * can reuse, share globally */ private static ObjectMapper mapper = new ObjectMapper(); public static ObjectMapper getMapper() { return mapper; } public static void setMapper(ObjectMapper mapper) { JsonUtils.mapper = mapper; } private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class); public static <T> T readFile(File file, Class<T> tClass) { try { return mapper.readValue(file, tClass); } catch (IOException e) { logger.warn("Parse json message exception .", e); return null; } } public static <T> T readInputStream(InputStream inputStream, Class<T> tClass) { try { return mapper.readValue(inputStream, tClass); } catch (IOException e) { logger.warn("Parse json message exception .", e); return null; } } public static String bean2Json(Object object) { try { return mapper.writeValueAsString(object); } catch (JsonProcessingException e) { logger.warn("fail to transfer bean to Json", e); return null; } } public static byte[] bean2Bytes(Object object) { try { return mapper.writeValueAsBytes(object); } catch (JsonProcessingException e) { logger.warn("fail to transfer bean to bytes", e); return null; } } public static <T> T json2bean(String json, Class<T> clazz) { try { return mapper.readValue(json, clazz); } catch (IOException e) { logger.debug("Parse json message exception. jsonString:{}, class:{}", json, clazz, e); return null; } } public static <T> T map2Bean(Map map, Class<T> tClass) { return mapper.convertValue(map, tClass); } public static <T> List<? super T> json2list(String json, Class<T> tClass) { JavaType type = getCollectionType(List.class, tClass); try { return mapper.readValue(json, type); } catch (IOException e) { logger.warn("fail to transfer json to list .", e); return null; } } public static Map<String, Object> json2Map(String json) { TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() { }; try { return mapper.readValue(json, typeRef); } catch (IOException e) { logger.warn("fail to transfer json to map .", e); return null; } } public static Map<String, Object> json2MapWithoutLog(String json) { TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() { }; try { return mapper.readValue(json, typeRef); } catch (IOException e) { return null; } } public static JavaType getCollectionType(Class<?> collectionClass, Class<?> elementClasses) { return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses); } } /** * Kryo序列化、反序列化类 * * @author Zhou Wenpei * @version 1.0 * @since 2023/8/11 */ @Slf4j public class KryoSerializeUtils { /** * 线上大都小于10K,由于粒度问题,无法查看细致的大小,暂定初始大小为5K */ private static final int KRYO_BUFFER_SIZE = 5 * 1024; private KryoSerializeUtils() { } /** * 线程不安全,通过ThreadLocal实现 */ private static final ThreadLocal<Kryo> KRYOS = ThreadLocal.withInitial(() -> { // 在此处配置kryo对象 Kryo kryo = new Kryo(); kryo.setRegistrationRequired(false); return kryo; }); /** * Kryo 序列化,序列化失败将返回空字节数组 */ public static byte[] bean2ByteArray(Object object) { try (Output output = new Output(KRYO_BUFFER_SIZE, -1)) { Kryo kryo = KRYOS.get(); kryo.writeObject(output, object); return output.toBytes(); } catch (Exception e) { log.warn("kryo serial object failed, exception :{}", e); return new byte[0]; } } /** * Kryo 反序列化,反序列化失败将返回空对象 */ public static <T> T byteArray2Bean(byte[] source, Class<T> destinationClass) { Kryo kryo = KRYOS.get(); try (Input input = new Input(source)) { return kryo.readObject(input, destinationClass); } catch (Exception e) { log.warn("kryo deserialize object failed, exception :{}", e); } return null; } public static void clearKryo() { KRYOS.remove(); } } public class StringUtils { private StringUtils() { } public static String generateUUID() { return UUID.randomUUID().toString().replace("-", ""); } } @Getter @NoArgsConstructor @SuperBuilder @AllArgsConstructor public abstract class BaseEvent<T> { protected String filterKey; protected long timeStamp; protected T message; } /** * 事件中心用于传递事件的类,eventStr为从消息中间件拿到的具体事件,反序列化工作由业务层完成 * * @author ludingyang * @version 1.0 * @since 2020/6/29. */ @Getter @NoArgsConstructor @SuperBuilder public final class Event extends BaseEvent<String> { public Event(String filterKey, String message) { this.filterKey = filterKey; this.message = message; } @Override public String toString() { return JsonUtils.bean2Json(this); } public void setTimeStamp(long timeStamp) { this.timeStamp = timeStamp; } public static Event toBean(String string) { return JsonUtils.json2bean(string, Event.class); } } /** * Event Center组件对外提供的方法 * * @author ludingyang * @version 1.0 * @since 2020/7/30. */ public interface EventCenter { /** * 获取到topic的partition数量 该接口只能获取到使用EventCenter register的topic分区数 量 * * @param topic topic名 * @return partition数量,如果是不存在的topic则为0 */ default Integer getPartitions(String topic) { return 0; } /** * 发送事件,会发送到任意分区上 * * @param topic 事件主题 * @param event 事件消息主体 */ default void send(@Nonnull String topic, @Nonnull Event event) { } /** * 发送事件,包含了回调方法 * * @param topic 事件主题 * @param event 事件消息主体 * @param eventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功后的回调方 法); onFailure(发送失败后的回调方法) */ default void send(@Nonnull String topic, @Nonnull Event event, EventFuture eventFuture) { } /** * 发送事件,相同key值的消息会发送到同一个分区上 * * @param topic 事件主题 * @param key 发送消息的key值,用于将相同key值的消息发送到同一分区中 * @param event 事件消息主体 */ default void send(@Nonnull String topic, String key, @Nonnull Event event) { } /** * 发送事件,相同key值的消息会发送到同一个分区上 * * @param topic 事件主题 * @param key 发送消息的key值,用于将相同key值的消息发送到同一分区中 * @param event 事件消息主体 * @param eventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功后的回调方 法); onFailure(发送失败后的回调方法) */ default void send(@Nonnull String topic, String key, @Nonnull Event event, EventFuture eventFuture) { } /** * 发送事件,消息会发送到分区partition上 * * @param topic 事件主题 * @param partition 分区 * @param event 事件消息主体 */ default void send(@Nonnull String topic, @Nonnull Integer partition, @Nonnull Event event) { } /** * 发送事件,消息会发送到分区partition上 * * @param topic 事件主题 * @param partition 分区 * @param event 事件消息主体 * @param eventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功后的回调方 法); onFailure(发送失败后的回调方法) */ default void send(@Nonnull String topic, @Nonnull Integer partition, @Nonnull Event event, EventFuture eventFuture) { } /** * 发送事件,会发送到任意分区上 * * @param topic 事件主题 * @param event 事件消息主体,如果serializeEnum采用Kryo序列化,event类型需要为 EventV2;如果采用Json序列化,event类型为Event * @param serializeEnum 采用的序列化方式 */ default void send(@Nonnull String topic, @Nonnull BaseEvent event, @Nonnull SerializeEnum serializeEnum) { } /** * 发送事件,包含了回调方法 * * @param topic 事件主题 * @param event 事件消息主体,如果serializeEnum采用Kryo序列化,event类型需要 为EventV2;如果采用Json序列化,event类型为Event * @param eventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功后的回调方 法); onFailure(发送失败后的回调方法) * @param serializeEnum 采用的序列化方式 */ default void send(@Nonnull String topic, @Nonnull BaseEvent event, GenericEventFuture eventFuture, @Nonnull SerializeEnum serializeEnum) { } /** * 发送事件,相同key值的消息会发送到同一个分区上 * * @param topic 事件主题 * @param key 发送消息的key值,用于将相同key值的消息发送到同一分区中 * @param event 事件消息主体,如果serializeEnum采用Kryo序列化,event类型需要为 EventV2;如果采用Json序列化,event类型为Event * @param serializeEnum 采用的序列化方式 */ default void send(@Nonnull String topic, String key, @Nonnull BaseEvent event, @Nonnull SerializeEnum serializeEnum) { } /** * 发送事件,相同key值的消息会发送到同一个分区上 * * @param topic 事件主题 * @param key 发送消息的key值,用于将相同key值的消息发送到同一分区中 * @param event 事件消息主体,如果serializeEnum采用Kryo序列化,event类型需要 为EventV2;如果采用Json序列化,event类型为Event * @param eventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功后的回调方 法); onFailure(发送失败后的回调方法) * @param serializeEnum 采用的序列化方式 */ default void send(@Nonnull String topic, String key, @Nonnull BaseEvent event, GenericEventFuture eventFuture, @Nonnull SerializeEnum serializeEnum) { } /** * 发送事件,消息会发送到分区partition上 * * @param topic 事件主题 * @param partition 分区 * @param event 事件消息主体,如果serializeEnum采用Kryo序列化,event类型需要为 EventV2;如果采用Json序列化,event类型为Event * @param serializeEnum 采用的序列化方式 */ default void send(@Nonnull String topic, @Nonnull Integer partition, @Nonnull BaseEvent event, @Nonnull SerializeEnum serializeEnum) { } /** * 发送事件,消息会发送到分区partition上 * * @param topic 事件主题 * @param partition 分区 * @param event 事件消息主体,如果serializeEnum采用Kryo序列化,event类型需要 为EventV2;如果采用Json序列化,event类型为Event * @param eventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功后的回调方 法); onFailure(发送失败后的回调方法) * @param serializeEnum 采用的序列化方式 */ default void send(@Nonnull String topic, @Nonnull Integer partition, @Nonnull BaseEvent event, GenericEventFuture eventFuture, @Nonnull SerializeEnum serializeEnum) { } /** * 注册处理广播事件的handler(默认分区分配策略为COOPERATIVE_STICKY) * * @param topic 主题 * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 */ default void registerBroadcast(@Nonnull String topic, @Nonnull EventHandler handler, @Nonnull ExecutorService executorService) { } /** * 注册处理广播事件的handler * * @param topic 主题 * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param partitionAssignorMode 分区分配策略 */ default void registerBroadcast(@Nonnull String topic, @Nonnull EventHandler handler, @Nonnull ExecutorService executorService, PartitionAssignorMode partitionAssignorMode) { } /** * 注册处理单播事件的handler(默认分区分配策略为COOPERATIVE_STICKY) * * @param topic 主题 * @param groupId 消费者组Id * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 */ default void registerUnicast(@Nonnull String topic, @Nonnull String groupId, @Nonnull EventHandler handler, @Nonnull ExecutorService executorService) { } /** * 注册处理单播事件的handler * * @param topic 主题 * @param groupId 消费者组Id * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param partitionAssignorMode 分区分配策略 */ default void registerUnicast(@Nonnull String topic, @Nonnull String groupId, @Nonnull EventHandler handler, @Nonnull ExecutorService executorService, PartitionAssignorMode partitionAssignorMode) { } /** * 注册处理广播事件的handler(不传线程池) * * @param topic 主题 * @param handler 事件处理类 * @param partitionAssignorMode 分区分配策略 */ default void registerBroadcastWithoutThreadPool(@Nonnull String topic, @Nonnull EventHandler handler, PartitionAssignorMode partitionAssignorMode) { } /** * 注册处理单播事件的handler(不传线程池) * * @param topic 主题 * @param groupId 消费者组 * @param handler 事件处理类 * @param partitionAssignorMode 分区分配策略 */ default void registerUnicastWithoutThreadPool(@Nonnull String topic, @Nonnull String groupId, @Nonnull EventHandler handler, PartitionAssignorMode partitionAssignorMode) { } /** * 解注册一个主题下的handler * * @param topic 主题 * @param handler 事件处理类 */ default void unregister(@Nonnull String topic, @Nonnull EventHandler handler) { } /** * 发送事件,会发送到任意分区上 * * @param topic 事件主题 * @param event 事件消息主体 */ default <T> void sendGenerically(@Nonnull String topic, @Nonnull T event) { } /** * 发送事件,包含了回调方法 * * @param topic 事件主题 * @param event 事件消息主体 * @param genericEventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功 后的回调方法); onFailure(发送失败后的回调方法) */ default <T> void sendGenerically(@Nonnull String topic, @Nonnull T event, GenericEventFuture<T> genericEventFuture) { } /** * 发送事件,相同key值的消息会发送到同一个分区上 * * @param topic 事件主题 * @param key 发送消息的key值,用于将相同key值的消息发送到同一分区中 * @param event 事件消息主体 */ default <T> void sendGenerically(@Nonnull String topic, String key, @Nonnull T event) { } /** * 发送事件,相同key值的消息会发送到同一个分区上 * * @param topic 事件主题 * @param key 发送消息的key值,用于将相同key值的消息发送到同一分区中 * @param event 事件消息主体 * @param genericEventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功 后的回调方法); onFailure(发送失败后的回调方法) */ default <T> void sendGenerically(@Nonnull String topic, String key, @Nonnull T event, GenericEventFuture<T> genericEventFuture) { } /** * 发送事件,消息会发送到分区partition上 * * @param topic 事件主题 * @param partition 分区 * @param event 事件消息主体 */ default <T> void sendGenerically(@Nonnull String topic, @Nonnull Integer partition, @Nonnull T event) { } /** * 发送事件,消息会发送到分区partition上 * * @param topic 事件主题 * @param partition 分区 * @param event 事件消息主体 * @param genericEventFuture 包含发送成功或失败后执行的回调方法:onSuccess(发送成功 后的回调方法); onFailure(发送失败后的回调方法) */ default <T> void sendGenerically(@Nonnull String topic, @Nonnull Integer partition, @Nonnull T event, GenericEventFuture<T> genericEventFuture) { } /** * 注册处理广播事件的handler(默认分区分配策略为COOPERATIVE_STICKY) * * @param topic 主题 * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param clazz 定义类 */ default <T> void registerBroadcastGenerically(@Nonnull String topic, @Nonnull GenericEventHandler<T> handler, @Nonnull ExecutorService executorService, @NonNull Class<T> clazz) { } /** * 注册处理广播事件的handler * * @param topic 主题 * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param partitionAssignorMode 分区分配策略 * @param clazz 定义类 */ default <T> void registerBroadcastGenerically(@Nonnull String topic, @Nonnull GenericEventHandler<T> handler, @Nonnull ExecutorService executorService, PartitionAssignorMode partitionAssignorMode, @NonNull Class<T> clazz) { } /** * 注册处理单播事件的handler(默认分区分配策略为COOPERATIVE_STICKY) * * @param topic 主题 * @param groupId 消费者组Id * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param clazz 定义类 */ default <T> void registerUnicastGenerically(@Nonnull String topic, @Nonnull String groupId, @Nonnull GenericEventHandler<T> handler, @Nonnull ExecutorService executorService, @NonNull Class<T> clazz) { } /** * 注册处理单播事件的handler * * @param topic 主题 * @param groupId 消费者组Id * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param partitionAssignorMode 分区分配策略 * @param clazz 定义类 */ default <T> void registerUnicastGenerically(@Nonnull String topic, @Nonnull String groupId, @Nonnull GenericEventHandler<T> handler, @Nonnull ExecutorService executorService, PartitionAssignorMode partitionAssignorMode, @NonNull Class<T> clazz) { } /** * 注册处理广播事件的handler(不传线程池) * * @param topic 主题 * @param handler 事件处理类 * @param partitionAssignorMode 分区分配策略 * @param clazz 定义类 */ default <T> void registerBroadcastWithoutThreadPoolGenerically(@Nonnull String topic, @Nonnull GenericEventHandler<T> handler, PartitionAssignorMode partitionAssignorMode, @NonNull Class<T> clazz) { } /** * 注册处理单播事件的handler(不传线程池) * * @param topic 主题 * @param groupId 消费者组 * @param handler 事件处理类 * @param partitionAssignorMode 分区分配策略 * @param clazz 定义类 */ default <T> void registerUnicastWithoutThreadPoolGenerically(@Nonnull String topic, @Nonnull String groupId, @Nonnull GenericEventHandler<T> handler, PartitionAssignorMode partitionAssignorMode, @NonNull Class<T> clazz) { } /** * 解注册一个主题下的handler * * @param topic 主题 * @param handler 事件处理类 */ default <T> void unregisterGenerically(@Nonnull String topic, @Nonnull GenericEventHandler<T> handler) { } /** * 在不销毁executorService的场景下,解注册单个topic * @param topic 主题 * @param handler 事件处理类 * @param isDestroyExecutorService 是否需要销毁线程池 */ default <T> void unregisterGenerically(@Nonnull String topic, @Nonnull GenericEventHandler<T> handler, boolean isDestroyExecutorService) { } /** * 在不销毁executorService的场景下,解注册单个topic * @param topic 主题 * @param eventHandler 事件处理类 * @param isDestroyExecutorService 是否需要销毁线程池 */ default void unregister(@Nonnull String topic, @Nonnull EventHandler eventHandler, boolean isDestroyExecutorService) { } /** * 注册处理广播事件的handler(默认分区分配策略为COOPERATIVE_STICKY) * * @param topic 主题 * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param serializeEnum 采用的序列化方式 */ default void registerBroadcast(@Nonnull String topic, @Nonnull GenericEventHandler handler, @Nonnull ExecutorService executorService, @Nonnull SerializeEnum serializeEnum) { } /** * 注册处理广播事件的handler * * @param topic 主题 * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param partitionAssignorMode 分区分配策略 * @param serializeEnum 采用的序列化方式 */ default void registerBroadcast(@Nonnull String topic, @Nonnull GenericEventHandler handler, @Nonnull ExecutorService executorService, PartitionAssignorMode partitionAssignorMode, @Nonnull SerializeEnum serializeEnum) { } /** * 注册处理单播事件的handler(默认分区分配策略为COOPERATIVE_STICKY) * * @param topic 主题 * @param groupId 消费者组Id * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param serializeEnum 采用的序列化方式 */ default void registerUnicast(@Nonnull String topic, @Nonnull String groupId, @Nonnull GenericEventHandler handler, @Nonnull ExecutorService executorService, @Nonnull SerializeEnum serializeEnum) { } /** * 注册处理单播事件的handler * * @param topic 主题 * @param groupId 消费者组Id * @param handler 事件处理类 * @param executorService 上层传递的处理业务的线程池 * @param partitionAssignorMode 分区分配策略 * @param serializeEnum 采用的序列化方式 */ default void registerUnicast(@Nonnull String topic, @Nonnull String groupId, @Nonnull GenericEventHandler handler, @Nonnull ExecutorService executorService, PartitionAssignorMode partitionAssignorMode, @Nonnull SerializeEnum serializeEnum) { } /** * 注册处理广播事件的handler(不传线程池) * * @param topic 主题 * @param handler 事件处理类 * @param partitionAssignorMode 分区分配策略 * @param serializeEnum 采用的序列化方式 */ default void registerBroadcastWithoutThreadPool(@Nonnull String topic, @Nonnull GenericEventHandler handler, PartitionAssignorMode partitionAssignorMode, @Nonnull SerializeEnum serializeEnum) { } /** * 注册处理单播事件的handler(不传线程池) * * @param topic 主题 * @param groupId 消费者组 * @param handler 事件处理类 * @param partitionAssignorMode 分区分配策略 * @param serializeEnum 采用的序列化方式 */ default void registerUnicastWithoutThreadPool(@Nonnull String topic, @Nonnull String groupId, @Nonnull GenericEventHandler handler, PartitionAssignorMode partitionAssignorMode, @Nonnull SerializeEnum serializeEnum) { } /** * 解注册所有的topic */ default void unregisterAllTopics() { } /** * 销毁EventCenter时释放资源 */ @PreDestroy default void destroy() { } } public interface EventFuture { /** * 发送成功后的回调函数 * * @param eventCenterSendResult 发送结果 */ void onSuccess(EventCenterSendResult eventCenterSendResult); /** * 发送失败后的回调函数 * * @param throwable 发送异常 */ void onFailure(Throwable throwable); } /** * Event Center处理监听到的Event事件,具体业务实现在各个模块进行 * * @author ludingyang * @version 1.0 * @since 2020/6/29. */ public interface EventHandler extends Handler { /** * 业务处理的方法 * * @param event 传递的消息封装类 */ void handleEvent(Event event); } @Getter @NoArgsConstructor @SuperBuilder @Slf4j @ToString public final class EventV2<T> extends BaseEvent<T> { public EventV2(String filterKey, T message) { this.filterKey = filterKey; this.message = message; } public void setTimeStamp(long timeStamp) { this.timeStamp = timeStamp; } } public static EventV2 toBean(byte[] bytes) { return KryoSerializeUtils.byteArray2Bean(bytes, EventV2.class); } public byte[] kryoSerialize() { return KryoSerializeUtils.bean2ByteArray(this); } /** * Producer可配置的回调函数(泛型接口 / EventV2接口) * * @author ludingyang * @version 1.0 * @since 2021/3/17 */ public interface GenericEventFuture<T> { /** * 发送成功后的回调函数 * * @param genericEventCenterSendResult 发送结果 */ void onSuccess(GenericEventCenterSendResult<T> genericEventCenterSendResult); /** * 发送失败后的回调函数 * * @param throwable 发送异常 */ void onFailure(Throwable throwable); } /** * Event Center处理监听到的事件,具体业务实现在各个模块进行(泛型接口) * * @author ludingyang * @version 1.0 * @since 2020/6/29. */ public interface GenericEventHandler<T> extends Handler { /** * 业务处理的方法 * * @param event 传递的消息封装类 */ void handleEvent(T event); } public interface Handler { /** * 重平衡之前可以调用执行 可以做一些简单的操作,不建议执行耗时操作,不然会拉长重平衡时间 对 于eager rebalance:STICKY,RANGE,ROUND_ROBIN;每次进行重平衡时都会触发一次。 * 对于cooperative rebalance:COOPERATIVE_STICKY;只有在consumer被分配的 partitions被主动销毁或者consumer准备离开consumer group时才会触发一次 */ default void doBeforeRebalance() { LogAccess.LOGGER.info("start to process rebalance!"); } /** * 重平衡之后可以调用执行 可以做一些简单的操作,不建议执行耗时操作,不然会拉长重平衡时间 每 次重平衡结束后会触发一次 */ default void doAfterRebalance() { LogAccess.LOGGER.info("ending rebalance!"); } 以上为eventcenter-api的全部代码,后续的开发将基于这些接口,请熟悉并了解每项功能
最新发布
09-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值