스프링 부팅 동적 구성이 활성화 여부 카프카, 플러그인의 형태로, 따라서 카프카 지원이 이루어 카프카 통합 후 할 수있는 방법입니다
다음도 1 (longc-플러그 - 카프카 예에서) 서브 모듈을 작성, POM 구성은 :
<? XML 버전 = "1.0"인코딩 = "UTF-8"?> <프로젝트의 xmlns = "http://maven.apache.org/POM/4.0.0"에 xmlns :이 xsi = "HTTP : //www.w3 .ORG / 2001 / 된 XMLSchema 인스턴스 " 는 xsi :의 schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd "> <부모> <artifactId를> longc </ artifactId를> <의 groupId> com.longc </의 groupId> <version>은 1.0 SNAPSHOT </ 버전> </ 부모> <modelVersion> 4.0.0 </ modelVersion> <artifactId를> longc- 플러그인 - 카프카 </ artifactId를> <이름> longc - 플러그인 - 카프카 </ 이름> <URL> http://www.example.com </ URL> <특성> <project.build.sourceEncoding> UTF-8 </project.build.sourceEncoding> <maven.compiler.source> 1.8 </maven.compiler.source> <maven.compiler.target> 1.8 </maven.compiler.target> </ 속성> <종속성> <! - 봄 -> <의존성> <의 groupId> org.springframework.kafka </의 groupId> <artifactId를> 스프링 카프카 </ artifactId를> <version>은 $ {스프링 kafka.version} </ 버전> </ 의존성> <의존성> <의 groupId> com.longc </의 groupId> <artifactId를> longc 코어 </ artifactId를> <version>은 1.0 SNAPSHOT </ 버전> </ 의존성> </ 의존성> </ 프로젝트>
봄 부팅 기본 패키지에 대한 다음 longc 코어 프로젝트
2, 카프카의 구성을 추가 :
봄 : 카프카 : 주소 #의 쉼표로 구분 된 목록 (카프카의 기본 포트 번호 9092) 초기 연결 카프카 클러스터를 구축하기위한 부트 스트랩-서버에서 : 127.0.0.1:9092 프로듀서 : #을 오류가 발생한 후, 메시지 재전송 수. 재시 번호 : 0 메시지 복수의 동일한 파티션으로 전송 될 필요가 #은 일괄 적으로 동일한 생산에 넣어. 이 매개 변수는 바이트의 수에 따라 계산 사용할 수있는 메모리의 배치 사이즈를 지정한다. BATCH 크기 번호 : 16384 #는 생산자의 메모리 버퍼의 크기를 설정합니다. 버퍼 메모리 # : 33,554,432 직렬화 키 # 키 직렬화 : org.apache.kafka.common.serialization.StringSerializer 직렬화 값 # 1 값 Serializer- : org.apache.kafka.common.serialization.StringSerializer의 #에서의 ACK = 0 : 성공 메시지 쓰기 전에 제조 업체는 서버로부터 어떤 응답을 기다리지 않습니다. # 용의 ACK의 = 1 : 한 클러스터의 리더 노드가 메시지를 수신 한, 생산자는 서버에서 성공적인 응답을 받게됩니다. #의 ACK를 = 모두 : 모든 메시지의 복제에 참여하는 모든 노드받은 경우에만, 생산자는 서버에서 성공적인 응답을 받게됩니다. ACK들 # :. 1 소비자 : 본원에서 사용되는 유형의 # 자동 제출 시간 간격 스프링 부트 2.X 버전은 LS, 1M, 2H, (d)와 같은 특정 형식을 충족하도록 요구되는 시간 값위한 # 커밋 간격 오토 - : LS 이 속성이 오프셋없이 읽기 무효 파티션에서 소비자 또는 어떤 프로세스에 대한 오프셋의 경우 지정 # : 경우에 # 최신 (기본값)가 오프셋 (offset)는,에서 소비자 무효 최신 기록 (소비자 후에 생성 시작 기록) 데이터를 읽기 시작하는 가장 빠른 # : 유효하지 않은 오프셋에서, 소비자가 기록의 시작 위치에서 파티션 읽기 가장 빠른 : #은 자동이 오프셋 - 초기화를 #을 데이터와 데이터 손실의 중복을 피하기 위해, 기본 값이 true, 자동 오프셋 제출, 그것은 false로 설정 한 다음 수동으로 오프셋 (offset)에 제출 될 수 # 있도록-자동 위탁 : 사실 직렬화 모드 키 # 키 -deserializer : org.apache.kafka.common.serialization.StringDeserializer # 청취자 : #의 안티 - 직렬화 값 디시리얼라이저 값 : org.apache.kafka.common.serialization.StringDeserializer의 # 리스너 컨테이너에서 실행되는 스레드 수입니다. # 동시성 : 5
참조는 구성 될 수있다 의미 https://spring.io/projects/spring-kafka#learn
3 카프카 구성 클래스 (스프링이 자기 달성 할 수 있고, 기본 매개 변수가 지정되지 배치)
예 :
/ ** * 카프카配置 * 2019년 6월 29일에 log.chang 작성. * / @Configuration @SuppressWarnings ( "모든") 공용 클래스 KafkaConfig { @Value ( "$ {spring.kafka.bootstrap - 서버}") 개인 문자열 bootstrapServers; @Value ( "$ {spring.kafka.listener.pool - 제한 시간 : 15000}") 개인 문자열 listenerPoolTimeout; @Value ( "$ {spring.kafka.producer.acks : -1}") 개인 문자열 producerAcks; @Value ( "$ {spring.kafka.producer.batch 크기 : 5}") 개인 문자열 producerBatchSize; @Value ( "$ {spring.kafka.consumer.group-ID : 기본적}") 개인 문자열 consumerGroupId을; @Value는 ( "$ {소비자. @Value는 ( "오토 $는 {commit-을 spring.kafka.consumer.enable : true로}") 개인 부울 consumerEnableAutoCommit, @value ( "{$ spring.kafka.consumer.max - 여론 조사 - 레코드 :. 5}") 개인 INT consumerMaxPollRecords; / ** * =========================== 생산자 배치 ============== ============ * / / ** * 생산자 구성 맵을 작성, ProducerConfig 구성 속성이 자동으로 부팅 봄보다 더 많은 것으로 구성되어 * / {) (개인지도 <문자열, 개체> producerProperties 지도 <문자열, 개체> 소품 = 새로운 새로운 HashMap의 <> (); props.put (ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); props.put (ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); props.put (ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); props.put (ProducerConfig.ACKS_CONFIG, producerAcks); props.put (ProducerConfig.BATCH_SIZE_CONFIG, producerBatchSize); //props.put(ProducerConfig.LINGER_MS_CONFIG, 500); 소품을 반환; } / ** *不使用봄 부팅的KafkaAutoConfiguration默认方式创建的DefaultKafkaProducerFactory,重新定义 * / @Bean ( "produceFactory") 공공 DefaultKafkaProducerFactory produceFactory는 () { 반환 새 DefaultKafkaProducerFactory (producerProperties ()); } / ** * 사용하지 KafkaTemplate는 KafkaAutoConfiguration 기본 스프링 부팅 재정의 생성 * / @Bean ( "kafkaTemplate") KafkaTemplate kafkaTemplate 공개 (DefaultKafkaProducerFactory produceFactory) { 신규 새로운 KafkaTemplate (produceFactory) 반환 } / ** * =================== 소비자 구성 ========================== * / / ** * 소비자 구성 속성 맵, 스프링 부팅보다 더 ConsumerConfig 구성 가능한 속성이 자동으로 구성 할 수 멀티 * / 개인지도 <문자열, 개체> consumerProperties () { 지도 <문자열, 개체> 소품 = 새로운 새로운 HashMap의 <> (); props.put (ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers) props.put (ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, consumerEnableAutoCommit); props.put (ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, listenerPoolTimeout) ; props.put (ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put (ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put (ConsumerConfig.MAX_POLL_RECORDS_CONFIG, consumerMaxPollRecords); props.put (ConsumerConfig.GROUP_ID_CONFIG, consumerGroupId); 소품을 반환; } / ** *不使用봄 부팅默认方式创建的DefaultKafkaConsumerFactory,重新定义创建方式 * / @Bean ( "consumerFactory") 공공 DefaultKafkaConsumerFactory consumerFactory는 () { 반환 새 DefaultKafkaConsumerFactory (consumerProperties ()); } @Bean ( "listenerContainerFactory") // 개인 소비자를 정의 공공 ConcurrentKafkaListenerContainerFactory listenerContainerFactory (DefaultKafkaConsumerFactory consumerFactory) { // 지정 DefaultKafkaConsumerFactory ConcurrentKafkaListenerContainerFactory 새로운 새로운 ConcurrentKafkaListenerContainerFactory 공장 = (); factory.setConsumerFactory (consumerFactory); //보고 요구 사항을 설정, 소비자 설명서의 ACK 모드를 설정 ) (setAckMode (ContainerProperties을 factory.getContainerProperties을. .AckMode.MANUAL_IMMEDIATE) (3)의 수를 당기는 대량 소비에 설치된 손잡이 // 메시지 수요가 설정 참조 factory.setConcurrency (3) )를 true로 factory.setBatchListener (; 공장 반환; } }
이 시점에서 나는 일반적인 도구를 할 수 있기를 바랍니다 소비, @KafkaListener 사용하여 프로젝트 kafkaTemplate 메시지 생산, 메시지 주석에 직접 주입, 따라서 다음과 같은 패키지를 작성되었을 수 :
메시지 이벤트 :
/ ** * 카프카 이벤트 데이터 . *를 2019년 7월 1일 ON log.chang 만든 * / @Data Public 클래스 KafkaEvent {<KafkaEventData 연장이 T> 공개 KafkaEvent (T 데이터) { this.data = 데이터; this.dataClazz = data.getClass () getName (); } / ** (소비자의 소비) * 데이터 타입 * / 개인 문자열 dataClazz; / ** * 카프카 메시지 데이터 * / ; 비공개 데이터 T } 자바 .io 오기 직렬화; / ** * 카프카는 이벤트 데이터 살았었다 . 2019년 7월 1일 ON * log.chang 만든을 * / 공용 클래스 KafkaEventData 구현을 직렬화 { 공공 KafkaEventData () { } }
메시징 :
/ ** * 카프카 이벤트 처리 카프카 kafkaEvent, 일반 서브 클래스를 사용하여 메시지를 전송 *와 KafkaEvent 접합 KafkaEventData *에 대응하는 소모성 KafkaEventData 메시지 핸들러 대응 * 2019년 6월 29일 ON log.chang을 만든. * / 공공 추상 클래스 KafkaEventHandler는 <KafkaEventData는 T를 확장> { 공공 추상적 무효 핸들 (문자열 키, T 이벤트); }
프로듀서 :
@Component @ SLF4J 공용 클래스 KafkaProducer { @Autowired 개인 KafkaTemplate <문자열, 문자열> kafkaTemplate; 공공 무효 보내기 (문자열 키, KafkaEvent 데이터) { (DEFAULT_TOPIC, 키, 데이터)를 전송; } 공공 무효 보내기 (문자열 항목, 문자열 키, KafkaEvent 데이터) { 경우 (데이터 == NULL) { 새로운 LongcException (RespCode.MUST_PARAM_NULL, RespCode.MUST_PARAM_NULL_MSG)를 던져; } 문자열 dataJson JsonUtil.toJsonSnake = (데이터); (StringUtil.isTrimBlank (dataJson는)) {경우 새로운 LongcException (RespCode.MUST_PARAM_NULL, RespCode.MUST_PARAM_NULL_MSG)를 던져; } 결과 (kafkaTemplate.send (주제, 키, dataJson), 주제, 키, dataJson); } / ** *指定分区 * * @param 파티션指定的分区 * / 공공 무효 보내기 (정수 파티션, 문자열 항목, 문자열 키, KafkaEvent 데이터) { (데이터 == NULL을) {경우 (RespCode.MUST_PARAM_NULL 새로운 LongcException을 던져, RespCode.MUST_PARAM_NULL_MSG); } 문자열 dataJson JsonUtil.toJsonSnake = (데이터); (StringUtil.isTrimBlank (dataJson는)) {경우 새로운 LongcException (RespCode.MUST_PARAM_NULL, RespCode.MUST_PARAM_NULL_MSG)를 던져; } 결과 (kafkaTemplate.send (주제, 파티션, 키, dataJson), 주제, 키, dataJson); } / ** * + 소인 지정된 파티션 * * @param 파티션 지정된 파티션 * @param의 타임 스탬프는 타임 스탬프를 기록 (밀리 초)의 시대입니다. 비어있는 경우, 생산자는 () 타임 스탬프 사용에 System.currentTimeMillis에 할당됩니다. * / 공공 무효 보내기 (파티션 정수, 문자열 주제, 문자열 키, 데이터 KafkaEvent, 롱 타임 스탬프) { (데이터 == NULL) {IF 던져 새로운 새로운 LongcException (RespCode.MUST_PARAM_NULL, RespCode.MUST_PARAM_NULL_MSG); } 문자열 dataJson = JsonUtil.toJsonSnake (데이터), IF (StringUtil.isTrimBlank (dataJson)) { 새로운 새로운 LongcException는 던져 (RespCode.MUST_PARAM_NULL, RespCode.MUST_PARAM_NULL_MSG); // 메시지 전송 실패 카프카 } 결과 (kafkaTemplate.send (주제, 파티션, 타임 스탬프, 키, dataJson), 주제, 키, dataJson); } 개인 무효 결과 (ListenableFuture <SendResult <문자열, 문자열 >> resFu 문자열 항목 문자열 키 문자열 dataJson) { //发送成功回调 SuccessCallback <SendResult <문자열, 문자열 >> successCallback = sendResult -> { // 카프카消息成功发送 log.info (MessageFormat.format ( "KafkaProducer 성공 항목을 보낼 -> {} 키 -> {} 데이터 -> {}".., sendResult.getProducerRecord () 주제 (), sendResult.getProducerRecord () 키 () ., sendResult.getProducerRecord () 값 ())); }; //发送失败回调 FailureCallback failureCallback = 전 -> {dataJson +; log.error (에서 errormsg, 예); 문자열에서 errormsg = "KafkaProducer 오류를 보내 topic->"+ 주제 + "키 ->"+ 키 + "데이터 ->"+ dataJson; 새로운 LongcException (에서 errormsg)를 던져; }; resFu.addCallback (successCallback, failureCallback); } }
소비자 :
@Component @ SLF4J @SuppressWarnings ( "모든") 공용 클래스 KafkaConsumer { 개인 정적 최종지도 <문자열 클래스> handlerClassMap = 새로운 HashMap의 <> (); 정적 { 시도 { 반사 반사 = 새로운 반사 ( "com.longc"); 클래스 handlerClazz = KafkaEventHandler.class; 설정의 <class> childHandlerClazzSet = reflections.getSubTypesOf (handlerClazz); 만약 (! childHandlerClazzSet = NULL) { (클래스 childHandlerClazz : childHandlerClazzSet)에 대한 { 하는 ParameterizedType 유형 = (하는 ParameterizedType) childHandlerClazz.getGenericSuperclass (); 문자열 유형 이름이 type.getActualTypeArguments = () [0] .getTypeName (); log.info ( "KafkaConsumer registryReceiver 유형 이름 -> childHandlerClazz {} -> {}"유형 이름, childHandlerClazz) handlerClassMap.put (유형 이름, childHandlerClazz) } } } 캐치 (예외 EX) { } } / ** * 설정 배치 listenerContainerFactory 풀 메시지 매개 변수가 목록 <ConsumerRecord <정수, 문자열 >> 그래서 , 그렇지 않으면 ConsumerRecord \ * / @KafkaListener (주제 = { "는 Default- TOPIC "}) 공공 무효 registryReceiver (ConsumerRecord <문자열, 문자열> 기록) { log.info ("KafkaConsumer registryReceiver 기록 -> {} ", 기록); 오프셋 // ConsumerRecord (주제 = DEFAULT 주제 파티션 = 0 = 5 CreateTime 더 = 1,561,971,499,451 직렬화 키 크기 = 14, 시리얼 값 크기 = 83, 헤더 =의 RecordHeaders (헤더 = [], isReadOnly의 = 거짓), 키 = 카프카 테스트 키, 값 = { "data_clazz": "com.longc.demo.entity.TestKafkaData", "데이터"{ "키": "K", "값": "V"}}) 문자열 키 record.key = (); 문자열 dataJson record.value = (); 문자열 dataClassName = JsonUtil.elementToObjSnake (dataJson, "data_clazz", String.class); 클래스를 clazz = ReflectUtil.getClass (dataClassName) <?>; KafkaEventData 데이터 = (KafkaEventData) JsonUtil.elementToObjSnake (dataJson "데이터"를 clazz); 만약 (! } 클래스 handlerClass = handlerClassMap.get (dataClassName) <?>; KafkaEventHandler 핸들러 = (KafkaEventHandler) ReflectUtil.instance (handlerClass); (처리기 == NULL의) 경우에 { 리턴; } handler.handle (키 데이터); } }
소비자를위한 일반적인 논리에 따라 클래스를 하위 취득 반영 org.reflections 패키지를 사용하는 소비자 프로세싱은 해당 처리 클래스 반영
플러그인 패키지 이상 사용 카프카 프로젝트 소개 및 스프링 부팅 구성 카프카 구성에 추가되고, 메시지 데이터 상속 카프카 메시지 객체 클래스의 정의는 다음 메시지 처리 클래스 (정의 된 클래스와 일반 데이터 메시지) 방식으로 구현 될 수있다 hanle을 상속