文章目录
一、EnableKafka注解
EnableKafka注解,引入KafkaListenerAnnotationBeanPostProcessor,收集类和方法所使用的KafkaListener注解,通过KafkaListenerContainerFactory,创建成对应的container listener,并注册成bean。同时,通过KafkaListenerConfigurer实现container listener更多个性化配置。
二、相关配置类
1. KafkaListenerAnnotationBeanPostProcessor
该类,主要用于收集上下文环境中,bean 类、方法上所使用的KafkaListener注解,合并相关信息后,注册成container listener。
// KafkaListenerAnnotationBeanPostProcessor
// 分别收集方法、类上KafkaListener注解信息,注册成container listener。
@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
// 收集类上使用KafkaListener注解。
Collection<KafkaListener> classLevelListeners = findListenerAnnotations(targetClass);
final boolean hasClassLevelListeners = classLevelListeners.size() > 0;
final List<Method> multiMethods = new ArrayList<>();
// 收集方法上,所标记使用的KafkaListener注解。
Map<Method, Set<KafkaListener>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
new MethodIntrospector.MetadataLookup<Set<KafkaListener>>() {
@Override
public Set<KafkaListener> inspect(Method method) {
// 由于方法上允许KafkaListener、KafkaListeners两类注册同时存在,且KafkaListeners包含多个KafkaListener注解。
// 因此,此处使用Set<KafkaListener>
Set<KafkaListener> listenerMethods = findListenerAnnotations(method);
return (!listenerMethods.isEmpty() ? listenerMethods : null);
}
});
// 类上使用KafkaListener时,需在方法上使用KafkaHandler注解,标记处理逻辑。
if (hasClassLevelListeners) {
Set<Method> methodsWithHandler = MethodIntrospector.selectMethods(targetClass,
(ReflectionUtils.MethodFilter) method ->
AnnotationUtils.findAnnotation(method, KafkaHandler.class) != null);
multiMethods.addAll(methodsWithHandler);
}
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(bean.getClass());
if (this.logger.isTraceEnabled()) {
this.logger.trace("No @KafkaListener annotations found on bean type: " + bean.getClass());
}
}
else {
// Non-empty set of methods
for (Map.Entry<Method, Set<KafkaListener>> entry : annotatedMethods.entrySet()) {
Method method = entry.getKey();
for (KafkaListener listener : entry.getValue()) {
// 将@KafkaListener与method,绑定成MethodKafkaListenerEndpoint,进行注册。
processKafkaListener(listener, method, bean, beanName);
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug(annotatedMethods.size() + " @KafkaListener methods processed on bean '"
+ beanName + "': " + annotatedMethods);
}
}
// 针对于类上使用的KafkaListener注解,绑定成MultiMethodKafkaListenerEndpoint,进行注册。
if (hasClassLevelListeners) {
processMultiMethodListeners(classLevelListeners, multiMethods, bean, beanName);
}
}
return bean;
}
// 针对于KafkaListener与Method,完善MethodKafkaListenerEndpoint,并进行注册。
protected void processListener(MethodKafkaListenerEndpoint<?, ?> endpoint, KafkaListener kafkaListener,
Object bean, Object adminTarget, String beanName) {
String beanRef = kafkaListener.beanRef();
if (StringUtils.hasText(beanRef)) {
this.listenerScope.addListener(beanRef, bean);
}
endpoint.setBean(bean);
// 根据bean、method创建InvocableHandlerMethod,后续通过invoke方法,进行中间件数据处理。
endpoint.setMessageHandlerMethodFactory(this.messageHandlerMethodFactory);
endpoint.setId(getEndpointId(kafkaListener));
// 用于设置消费者的group.id属性。
// 当配置KafkaListener.groupId时,直接使用该属性;kafkaListener.idIsGroup配置为true,且设置KafkaListener.id属性,则使用id属性。
endpoint.setGroupId(getEndpointGroupId(kafkaListener, endpoint.getId()));
// 根据KafkaListener注解中,所使用的topic三种监听方式,进行相关属性设置。
endpoint.setTopicPartitions(resolveTopicPartitions(kafkaListener));
endpoint.setTopics(resolveTopics(kafkaListener));
endpoint.setTopicPattern(resolvePattern(kafkaListener));
// 设置client.id信息,根据此设置,在broker中,可用于查询相关kafka日志。
endpoint.setClientIdPrefix(resolveExpressionAsString(kafkaListener.clientIdPrefix(),
"clientIdPrefix"));