spring-kafka消费者源码详解

@EnableKafka注解

此注解会import一个类KafkaBootstrapConfiguration,这个类会创建2个bean:KafkaListenerAnnotationBeanPostProcessor和KafkaListenerEndpointRegistry

@Configuration
public class KafkaBootstrapConfiguration {

	@SuppressWarnings("rawtypes")
	@Bean(name = KafkaListenerConfigUtils.KAFKA_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public KafkaListenerAnnotationBeanPostProcessor kafkaListenerAnnotationProcessor() {
		return new KafkaListenerAnnotationBeanPostProcessor();
	}

	@Bean(name = KafkaListenerConfigUtils.KAFKA_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME)
	public KafkaListenerEndpointRegistry defaultKafkaListenerEndpointRegistry() {
			
		return new KafkaListenerEndpointRegistry();
	}

}

KafkaListenerAnnotationBeanPostProcessor方法详解(扫描包含KafkaListener和KafkaListeners注解的bean和method并注册endpoint)

public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
		if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
			Class targetClass = AopUtils.getTargetClass(bean);
			//扫描所有类上是否有注解,结合KafkaHandler注解一起使用
			Collection classLevelListeners = findListenerAnnotations(targetClass);
			final boolean hasClassLevelListeners = classLevelListeners.size() > 0;
			final List multiMethods = new ArrayList<>();
			//扫描当前bean的所有method是否有KafkaListener注解,并且将方法上有此注解放入在map中
			Map> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
					(MethodIntrospector.MetadataLookup>) method -> {
						Set listenerMethods = findListenerAnnotations(method);
						return (!listenerMethods.isEmpty() ? listenerMethods : null);
					});
			//如果类上面有KafkaListener注解,继续扫面当前类的所有方法中是否有@KafkaHandler注解,个人理解这两个注解结合使用的场景是用在
			//可以减少同一个topic消费时候的对象参数转换,最终将扫描的结果放在Set对象中
		    if (hasClassLevelListeners) {
				Set methodsWithHandler = MethodIntrospector.selectMethods(targetClass,
						(ReflectionUtils.MethodFilter) method ->
								AnnotationUtils.findAnnotation(method, KafkaHandler.class) != null);
				multiMethods.addAll(methodsWithHandler);
			}
			//nonAnnotatedClasses这个属性后面阅读源码的过程中没看到使用,先不管
		    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 {
				//如果当前项目扫描到了@KafkaListener注解标注的方法,则去循环去注册endpoint(这里的一个方法的一个注解就是一个endpoint,因为一个方法可以监听不同的队列的)
				for (Map.Entry> entry : annotatedMethods.entrySet()) {
					Method method = entry.getKey();
					for (KafkaListener listener : entry.getValue()) {
						//主要看这里,处理方法上包含KafkaListener的method
						processKafkaListener(listener, method, bean, beanName);
					}
				}
			}
			if (hasClassLevelListeners) {
			 	//主要看这里,处理类上面包含KafkaListener和方法上包含KafkaHandler的注册,和上面processKafkaListener最终调用的是一个方法processListener,只不过这个是一个注解对应
				//多个方法,上面是一个注解对应一个方法,所以这里不再展开,直接看processListener方法。都是去注册endpoint,注意一个KafkaListener注解和endpoint是一一对应的。不管标记在
				//方法上还是类上
			     processMultiMethodListeners(classLevelListeners, multiMethods, bean, beanName);
			}
		}
		return bean;
	}

最终都会调用到processListener方法中(从注解中获取数据放在endpoint对象中并注册KafkaListenerEndpointRegistrar,每一个KafkaListener标注的方法或者类为一个endpoint)

 
 

你可能感兴趣的:(java-spring,java,java,spring,kafka)