рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░
рдЗрд╡реЗрдВрдЯ рдбреНрд░рд┐рд╡рди рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдФрд░ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ
рдЕрдкрд╛рдЪреЗ рдХрд╛рдлреНрдХрд╛ рдиреЗ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдмрд╣реБрдд рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд┐рдпрд╛ рд╣реИред рдШрдЯрдирд╛-рд╕рдВрдЪрд╛рд▓рд┐рдд рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХрд╛ рдкреВрд░рд╛ рд▓рд╛рдн рдЙрдард╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдШрдЯрдирд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рддрдВрддреНрд░ рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХреБрдЫ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрдкрдпреЛрдЧ рдкрд░рд┐рджреГрд╢реНрдп / рдкреНрд░рд╡рд╛рд╣ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рдирдХреЗ рд▓рд┐рдП рдПрдХ
рд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдЕрдиреБрд░реЛрдз-рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд╢рдмреНрджрд╛рд░реНрде рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдпрд╣ рд░рд┐рд▓реАрдЬрд╝ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐
рдЕрдкрд╛рдЪреЗ рдХрд╛рдлреНрдХрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ
рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ-рд░рд┐рд╕реНрдкрд╛рдВрд╕ рдХреЛ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПред
@Middle_java рджреНрд╡рд╛рд░рд╛
рдЕрдиреБрд╡рд╛рджрд┐рддрдореВрд▓ рд▓реЗрдЦ рджрд┐рдирд╛рдВрдХ: реирем рдЕрдХреНрдЯреВрдмрд░ реирежрез October
рдЕрдкрд╛рдЪреЗ рдХрд╛рдлреНрдХрд╛ рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЕрдкрд╛рдЪреЗ рдХрд╛рдлреНрдХрд╛ рдХреЗ рд▓рд┐рдП
рдЕрдиреБрд░реЛрдз-рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╢рдмреНрджрд╛рд░реНрде рдкреНрд░рд╛рдХреГрддрд┐рдХ рдирд╣реАрдВ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрд╣ рдЪреБрдиреМрддреА рдирдИ рдирд╣реАрдВ рд╣реИред рдПрдВрдЯрд░рдкреНрд░рд╛рдЗрдЬрд╝ рдПрдХреАрдХрд░рдг рдкреИрдЯрд░реНрди
рдЕрдиреБрд░реЛрдз-рдЙрддреНрддрд░ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЪреИрдирд▓реЛрдВ рдкрд░ рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╕рдВрджреЗрд╢ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд┐рджреНрдз рддрдВрддреНрд░ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:
рд░рд┐рдЯрд░реНрди рдПрдбреНрд░реЗрд╕ рдкреИрдЯрд░реНрди
рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдиреБрд░реЛрдз рдХреЗ рд╕рд╛рде рдПрдХ рдореИрдХреЗрдирд┐рдЬреНрдо рдХреЗ рд╕рд╛рде
рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ-рд░рд┐рдкреНрд▓рд╛рдИ рдкреИрдЯрд░реНрди рдХрд╛ рдЕрдиреБрдкрд╛рд▓рди рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдкрддрд╛ рднреЗрдЬрд╛ рдЬрд╛ рд╕рдХреЗред

рд╣рд╛рд▓ рд╣реА рдореЗрдВ,
рд╕реНрдкреНрд░рд┐рдВрдЧ рдХрд╛рдлреНрдХрд╛ 2.1.3 рдиреЗ "рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рд░рд┐рдкреНрд▓рд╛рдИ" рдкреИрдЯрд░реНрди рдмреЙрдХреНрд╕ рд╕реЗ рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рд╛, рдФрд░ рд╕рдВрд╕реНрдХрд░рдг
2.2 рдореЗрдВ рдЗрд╕рдХреЗ рдХреБрдЫ рдЦреБрд░рджрд░реЗрдкрди рдХреЛ рдкреЙрд▓рд┐рд╢ рдХрд┐рдпрд╛ рдЧрдпрд╛ред рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдпрд╣ рд╕рдорд░реНрдерди рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:
рдХреНрд▓рд╛рдЗрдВрдЯ рд╕рд╛рдЗрдб: рдЙрддреНрддрд░ рджреЗрдирд╛ KafkaTemplate
рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХрд╛ рд╕реБрд╡рд┐рдЦреНрдпрд╛рдд рдЕрдореВрд░реНрдд рд╕реНрдкреНрд░рд┐рдВрдЧ рдореЗрдВ рдЕрдиреБрд░реЛрдз-рдЙрддреНрддрд░ рддрдВрддреНрд░ рдХреЗ рдХреНрд▓рд╛рдЗрдВрдЯ рднрд╛рдЧ рдХреЗ рд▓рд┐рдП рдЖрдзрд╛рд░ рдмрдирд╛рддрд╛ рд╣реИред
@Bean public ReplyingKafkaTemplate < String, Request, Reply > replyKafkaTemplate( ProducerFactory < String, Request > pf, KafkaMessageListenerContainer < String, Reply > lc) { return new ReplyingKafkaTemplate < > (pf, lc); }
рдпрд╣рд╛рдБ рдкрд░ рд╕рдм рдХреБрдЫ рдмрд╣реБрдд рд╕реАрдзрд╛ рд╣реИ: рд╣рдо
рдЙрддреНрддрд░ рджреЗрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ KafkaTemplate , рдЬреЛ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреБрдВрдЬреА рдХреЗ рд╕рд╛рде рдЕрдиреБрд░реЛрдз рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИ рдФрд░ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреБрдВрдЬреА рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, AskKafkaTemplate рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдЙрддреНрдкрд╛рджрдХ рд╡рд┐рдирд┐рдпрд╛рдордХ рдЕрдиреБрд░реЛрдз, ConsumerFactory рд░рд┐рд╕реНрдкрд╛рдВрд╕ рдФрд░ MessageListenerContainer рдХреЗ рд╕рд╛рде рдЙрдкрдпреБрдХреНрдд рдЙрдкрднреЛрдХреНрддрд╛ рдФрд░ рдирд┐рд░реНрдорд╛рддрд╛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕рд▓рд┐рдП, рдЖрд╡рд╢реНрдпрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдмрд╣реБрдд рд╡рдЬрдирджрд╛рд░ рд╣реИ:
@Value("${kafka.topic.car.reply}") private String replyTopic; @Bean public Map < String, Object > consumerConfigs() { Map < String, Object > props = new HashMap < > (); props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class); props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); return props; } @Bean public Map < String, Object > producerConfigs() { Map < String, Object > props = new HashMap < > (); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); return props; } @Bean public ProducerFactory < String, Request > requestProducerFactory() { return new DefaultKafkaProducerFactory < > (producerConfigs()); } @Bean public ConsumerFactory < String, Reply > replyConsumerFactory() { return new DefaultKafkaConsumerFactory < > (consumerConfigs(), new StringDeserializer(), new JsonSerializer < Reply > ()); } @Bean public KafkaMessageListenerContainer < String, Reply > replyListenerContainer() { ContainerProperties containerProperties = new ContainerProperties(replyTopic); return new KafkaMessageListenerContainer < > (replyConsumerFactory(), containerProperties); }
рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЕрдиреБрд░реЛрдз рднреЗрдЬрдиреЗ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
replKafkaTemplate рдХрд╛ рдЙрдкрдпреЛрдЧ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
@Value("${kafka.topic.car.request}") private String requestTopic; @Value("${kafka.topic.car.reply}") private String replyTopic; @Autowired private ReplyingKafkaTemplate < String, Request, Reply > requestReplyKafkaTemplate; ... RequestReply request = RequestReply.request(...);
рдмрд╣реБрдд рд╕рд╛рд░реЗ рдмреЙрдпрд▓рд░рдкреНрд▓реЗрдЯ рдФрд░ рдПрдХ рдирд┐рдореНрди-рд╕реНрддрд░реАрдп рдПрдкреАрдЖрдИ рднреА рд╣реИ, рдФрд░ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЖрдзреБрдирд┐рдХ
рдХрдореНрдкреЗрдЯрд┐рдмрд▓ рд╕рд┐рд╡рдиреА рдХреЗ рдмрдЬрд╛рдп рдпрд╣ рдЕрдкреНрд░рдЪрд▓рд┐рдд
рд╢реНрд░рд╡рдгрдпреЛрдЧреНрдп рд╕реАрд╡рди рдПрдкреАрдЖрдИ рднреА рд╣реИред
requestReplyKafkaTemplate ,
KafkaHeaders.CORRELATION_ID рд╢реАрд░реНрд╖рдХ рдмрдирд╛рдиреЗ рдФрд░ рд╕реЗрдЯ рдХрд░рдиреЗ рдХрд╛ рдзреНрдпрд╛рди рд░рдЦрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ
KafkaHeaders.REPLY_TOPIC рд╢реАрд░реНрд╖рдХ рд╕реЗрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдХреГрдкрдпрд╛ рдпрд╣ рднреА рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЙрддреНрддрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рд╡рд┐рд╖рдп рдЙрддреНрддрд░ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдЕрдирдЬрд╛рдиреЗ рдореЗрдВ
рдерд╛ ред рдХреБрдЫ рдЫреАред рдирд╣реАрдВ рдХрд╛рдлреА рдореИрдВ рд╡рд╕рдВрдд рдЕрдореВрд░реНрдд рд╕реЗ рдХреНрдпрд╛ рдЙрдореНрдореАрдж рдереАред
рд╕рд░реНрд╡рд░ рд╕рд╛рдЗрдб: @SendTo
рд╕рд░реНрд╡рд░ рдХреА рдУрд░ рд╕реЗ, рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рд╡рд┐рд╖рдп рдкрд░ рд╕реБрдирдиреЗ рд╡рд╛рд▓реЗ рд╕рд╛рдорд╛рдиреНрдп
рдХрд╛рдлрд╝реНрдХрд╛рд▓рд┐рд╕реНрдЯрдирд░ рдХреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдВрджреЗрд╢ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
@SendTo рдПрдиреЛрдЯреЗрд╢рди рдХреЗ рд╕рд╛рде рдЕрддрд┐рд░рд┐рдХреНрдд рд░реВрдк рд╕реЗ рд╕рдЬрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╢реНрд░реЛрддрд╛ рд╡рд┐рдзрд┐ рджреНрд╡рд╛рд░рд╛ рд▓реМрдЯрд╛рдИ рдЧрдИ рд╡рд╕реНрддреБ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдВрджреЗрд╢ рдореЗрдВ рд▓рдкреЗрдЯреА рдЬрд╛рддреА рд╣реИ,
CORRELATION_ID рдХреЛ рдЬреЛрдбрд╝рд╛
рдЬрд╛рддрд╛ рд╣реИ
, рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛
REPLY_TOPIC рд╢реАрд░реНрд╖ рд▓реЗрдЦ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╡рд┐рд╖рдп рдореЗрдВ рдкреНрд░рдХрд╛рд╢рд┐рдд рд╣реЛрддреА рд╣реИред
@Bean public Map < String, Object > consumerConfigs() { Map < String, Object > props = new HashMap < > (); props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonSerializer.class); props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); return props; } @Bean public Map < String, Object > producerConfigs() { Map < String, Object > props = new HashMap < > (); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); return props; } @Bean public ConsumerFactory < String, Request > requestConsumerFactory() { return new DefaultKafkaConsumerFactory < > (consumerConfigs(), new StringDeserializer(), new JsonSerializer < Request > ()); } @Bean public KafkaListenerContainerFactory < ConcurrentMessageListenerContainer < String, Request >> requestListenerContainerFactory() { ConcurrentKafkaListenerContainerFactory < String, Request > factory = new ConcurrentKafkaListenerContainerFactory < > (); factory.setConsumerFactory(requestConsumerFactory()); factory.setReplyTemplate(replyTemplate()); return factory; } @Bean public ProducerFactory < String, Reply > replyProducerFactory() { return new DefaultKafkaProducerFactory < > (producerConfigs()); } @Bean public KafkaTemplate < String, Reply > replyTemplate() { return new KafkaTemplate < > (replyProducerFactory()); }
рдпрд╣рд╛рдБ рдХреБрдЫ рд╡рд┐рдиреНрдпрд╛рд╕ рднреА рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рд▓реЗрдХрд┐рди рд╢реНрд░реЛрддрд╛ рд╡рд┐рдиреНрдпрд╛рд╕ рд╕рд░рд▓ рд╣реИ:
@KafkaListener(topics = "${kafka.topic.car.request}", containerFactory = "requestListenerContainerFactory") @SendTo() public Reply receive(Request request) { Reply reply = ...; return reply; }
рд▓реЗрдХрд┐рди рдЙрдкрднреЛрдХреНрддрд╛ рдХреЗ рдХрдИ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛?
рдЬрдм рддрдХ рд╣рдо рдЙрдкрднреЛрдХреНрддрд╛ рдХреЗ рдХрдИ рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддрдм рддрдХ рд╕рдм рдХреБрдЫ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХрдИ рдЧреНрд░рд╛рд╣рдХ рдЙрджрд╛рд╣рд░рдг рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рд╣реА рдЧреНрд░рд╛рд╣рдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рднреЗрдЬреА рдЬрд╛рдПред рд╕реНрдкреНрд░рд┐рдВрдЧ рдХрд╛рдлреНрдХрд╛ рдкреНрд░рд▓реЗрдЦрди рдорд╛рдирддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдЙрдкрднреЛрдХреНрддрд╛ рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп рд╡рд┐рд╖рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдпрд╛ рдХрд┐ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд
рдХрд╛рдлреНрдХрд╛рд╣реЗрдбрд░реНрд╕ рд╣реЗрдбрд░ рдореВрд▓реНрдп рдЕрдиреБрд░реЛрдз рдХреЗ рд╕рд╛рде рднреЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИред
RESPONSE_PARTITION рдПрдХ рдЪрд╛рд░-рдмрд╛рдЗрдЯ рдлрд╝реАрд▓реНрдб рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдкреВрд░реНрдгрд╛рдВрдХ рдЕрдиреБрднрд╛рдЧ рд╕рдВрдЦреНрдпрд╛ рдХрд╛ BIG-ENDRIT рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рд╣реИред рд╡рд┐рднрд┐рдиреНрди рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╡рд┐рд╖рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдмрд╣реБрдд рд▓рдЪреАрд▓рд╛ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╕реНрдкрд╖реНрдЯ
REPLY_PARTITION рд╕реЗрдЯрд┐рдВрдЧ
рдЪреБрдирддреЗ рд╣реИрдВред рдлрд┐рд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдкрддрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЙрд╕реЗ рдХрд┐рд╕ рдкрд╛рд░реНрдЯреАрд╢рди рдХреЛ рд╕реМрдВрдкрд╛ рдЧрдпрд╛ рд╣реИред рдкреНрд░рд▓реЗрдЦрди рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╡рд┐рднрд╛рдЬрди рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрдкрд╖реНрдЯ рд╡рд┐рдиреНрдпрд╛рд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реИред рдЖрдЗрдП рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:
@Value("${kafka.topic.car.reply.partition}") private int replyPartition; ... @Bean public KafkaMessageListenerContainer < String, RequestReply > replyListenerContainer() { ContainerProperties containerProperties = new ContainerProperties(replyTopic); TopicPartitionInitialOffset initialOffset = new TopicPartitionInitialOffset(replyTopic, replyPartition); return new KafkaMessageListenerContainer < > (replyConsumerFactory(), containerProperties, initialOffset); } private static byte[] intToBytesBigEndian(final int data) { return new byte[] { (byte)((data >> 24) & 0xff), (byte)((data >> 16) & 0xff), (byte)((data >> 8) & 0xff), (byte)((data >> 0) & 0xff), }; } ... record.headers().add(new RecordHeader(KafkaHeaders.REPLY_TOPIC, requestReplyTopic.getBytes())); record.headers().add(new RecordHeader(KafkaHeaders.REPLY_PARTITION, intToBytesBigEndian(replyPartition))); RequestReplyFuture < String, RequestReply, RequestReply > sendAndReceive = requestReplyKafkaTemplate.sendAndReceive(record); ...
рдмрд╣реБрдд рд╕реБрдВрджрд░ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдЖрд╡рд╢реНрдпрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╡реНрдпрд╛рдкрдХ рд╣реИ рдФрд░ рдПрдкреАрдЖрдИ рдирд┐рдореНрди рд╕реНрддрд░ рджрд┐рдЦрддрд╛ рд╣реИред рд╡рд┐рднрд╛рдЬрди рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдмрдврд╝рд╛рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдЬрдЯрд┐рд▓ рдмрдирд╛рддреА рд╣реИред рдЬрд╛рд╣рд┐рд░ рд╣реИ, рдЖрдк рдмреЗрд╣рддрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдФрд░ рд╡рд┐рднрд╛рдЬрди рдХреЗ рд▓рд┐рдП рд╡рд┐рд╖рдп рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг encapsulating
рдЪрд▓реЛ
рд░рд┐рдЯрд░реНрди рдПрдбреНрд░реЗрд╕ рдкреИрдЯрд░реНрди рдХреЛ рдПрдирдХреИрдкреНрд╕реБрд▓реЗрдЯ рдХрд░рдХреЗ рд╢реБрд░реВ рдХрд░реЗрдВ, рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдФрд░ рд╡рд┐рднрд╛рдЬрди рдХреЗ рд▓рд┐рдП рд╡рд┐рд╖рдп рдХреЗ рд╕рд╛рде рдЧреБрдЬрд░рдирд╛ред рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╖рдп рдХреЛ
RequestReplyTemplate рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЗрд╕рд▓рд┐рдП, рдПрдкреАрдЖрдИ рдореЗрдВ рдмрд┐рд▓реНрдХреБрд▓ рднреА рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЬрдм рдХрд┐рд╕реА рдЙрддреНрддрд░ рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд╛рдЬрди рдХреА рдмрд╛рдд рдЖрддреА рд╣реИ, рддреЛ рд╣рдо рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд рдХрд░реЗрдВрдЧреЗ: рдЙрддреНрддрд░ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╖рдп рд╢реНрд░реЛрддрд╛ рдХреЛ рд╕реМрдВрдкреЗ рдЧрдП рд╡рд┐рднрд╛рдЬрди рдХреЛ рдирд┐рдХрд╛рд▓реЗрдВ, рдФрд░ рдЗрд╕ рд╡рд┐рднрд╛рдЬрди рдХреЛ рд╕реНрд╡рддрдГ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░реЗрдВред рдЗрд╕рд╕реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдЗрди рд╣реЗрдбрд░ рдХреА рджреЗрдЦрднрд╛рд▓ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддреА рд╣реИред
рдЙрд╕реА рд╕рдордп, рдЖрдЗрдП рдорд╛рдирдХ
KafkaTemplate рдХреА рддрд░рд╣ рдПрдкреАрдЖрдИ рдХреЛ рднреА
рджреЗрдЦреЗрдВ ( рд╕рд░рд▓реАрдХреГрдд рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ
рд╕рд╛рде SendAndReceive () рд╡рд┐рдзрд┐
рдХреЛ рдУрд╡рд░рд▓реЛрдб рдХрд░реЗрдВ рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╡рд┐рд╖рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдВрдмрдВрдзрд┐рдд рдЕрддрд┐рднрд╛рд░рд┐рдд рддрд░реАрдХреЛрдВ рдХреЛ рдЬреЛрдбрд╝реЗрдВ):
public class PartitionAwareReplyingKafkaTemplate < K, V, R > extends ReplyingKafkaTemplate < K, V, R > { public PartitionAwareReplyingKafkaTemplate(ProducerFactory < K, V > producerFactory, GenericMessageListenerContainer < K, R > replyContainer) { super(producerFactory, replyContainer); } private TopicPartition getFirstAssignedReplyTopicPartition() { if (getAssignedReplyTopicPartitions() != null && getAssignedReplyTopicPartitions().iterator().hasNext()) { TopicPartition replyPartition = getAssignedReplyTopicPartitions().iterator().next(); if (this.logger.isDebugEnabled()) { this.logger.debug("Using partition " + replyPartition.partition()); } return replyPartition; } else { throw new KafkaException("Illegal state: No reply partition is assigned to this instance"); } } private static byte[] intToBytesBigEndian(final int data) { return new byte[] { (byte)((data >> 24) & 0xff), (byte)((data >> 16) & 0xff), (byte)((data >> 8) & 0xff), (byte)((data >> 0) & 0xff), }; } public RequestReplyFuture < K, V, R > sendAndReceiveDefault(@Nullable V data) { return sendAndReceive(getDefaultTopic(), data); } public RequestReplyFuture < K, V, R > sendAndReceiveDefault(K key, @Nullable V data) { return sendAndReceive(getDefaultTopic(), key, data); } ... public RequestReplyFuture < K, V, R > sendAndReceive(String topic, @Nullable V data) { ProducerRecord < K, V > record = new ProducerRecord < > (topic, data); return doSendAndReceive(record); } public RequestReplyFuture < K, V, R > sendAndReceive(String topic, K key, @Nullable V data) { ProducerRecord < K, V > record = new ProducerRecord < > (topic, key, data); return doSendAndReceive(record); } ... @Override public RequestReplyFuture < K, V, R > sendAndReceive(ProducerRecord < K, V > record) { return doSendAndReceive(record); } protected RequestReplyFuture < K, V, R > doSendAndReceive(ProducerRecord < K, V > record) { TopicPartition replyPartition = getFirstAssignedReplyTopicPartition(); record.headers() .add(new RecordHeader(KafkaHeaders.REPLY_TOPIC, replyPartition.topic().getBytes())) .add(new RecordHeader(KafkaHeaders.REPLY_PARTITION, intToBytesBigEndian(replyPartition.partition()))); return super.sendAndReceive(record); } }
рдЕрдЧрд▓рд╛ рдЪрд░рдг: рдЕрдзрд┐рдХ рдЖрдзреБрдирд┐рдХ
рдХрдВрдкреНрд▓реАрдЯреЗрдмрд▓ рдлрд╝реЙрд░реЗрд╕реНрдЯ рдХреЗ рд▓рд┐рдП
рд╕реБрдиреЗ рдЬрд╛рдиреЗ
рдпреЛрдЧреНрдп рд╕рд┐рд╡рдиреА рдХреЛ рдЕрдкрдирд╛рдирд╛ред
public class CompletableFutureReplyingKafkaTemplate < K, V, R > extends PartitionAwareReplyingKafkaTemplate < K, V, R > { public CompletableFutureReplyingKafkaTemplate(ProducerFactory < K, V > producerFactory, GenericMessageListenerContainer < K, R > replyContainer) { super(producerFactory, replyContainer); } public CompletableFuture < R > requestReplyDefault(V value) { return adapt(sendAndReceiveDefault(value)); } public CompletableFuture < R > requestReplyDefault(K key, V value) { return adapt(sendAndReceiveDefault(key, value)); } ... public CompletableFuture < R > requestReply(String topic, V value) { return adapt(sendAndReceive(topic, value)); } public CompletableFuture < R > requestReply(String topic, K key, V value) { return adapt(sendAndReceive(topic, key, value)); } ... private CompletableFuture < R > adapt(RequestReplyFuture < K, V, R > requestReplyFuture) { CompletableFuture < R > completableResult = new CompletableFuture < R > () { @Override public boolean cancel(boolean mayInterruptIfRunning) { boolean result = requestReplyFuture.cancel(mayInterruptIfRunning); super.cancel(mayInterruptIfRunning); return result; } };
рд╣рдо рдЗрд╕реЗ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рдкреИрдХ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдПрдкреАрдЖрдИ рд╣реИ рдЬреЛ рд╕реНрдкреНрд░рд┐рдВрдЧ
рдХреЗ рдореБрдЦреНрдп рдбрд┐рдЬрд╛рдЗрди рджрд░реНрд╢рди,
"рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкрд░ рдХрдиреНрд╡реЗрдВрд╢рди" рдХреЗ рд╕рд╛рде рдЕрдзрд┐рдХ рд╕реБрд╕рдВрдЧрдд рд╣реИред рдпрд╣рд╛рдБ рдЕрдВрддрд┐рдо рдЧреНрд░рд╛рд╣рдХ рдХреЛрдб рд╣реИ:
@Autowired private CompletableFutureReplyingKafkaTemplate < String, Request, Reply > requestReplyKafkaTemplate; ... requestReplyKafkaTemplate.requestReply(request).thenAccept(reply - > System.out.println("Reply: " + reply.toString()); );
рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рджреЗрдирд╛
рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдХрд╛рдлреНрдХрд╛ 2.2 рдХреЗ рд▓рд┐рдП рд╕реНрдкреНрд░рд┐рдВрдЧ рдЕрдкрд╛рдЪреЗ рдХрд╛рдлреНрдХрд╛ рдореЗрдВ
рдЕрдиреБрд░реЛрдз-рдЙрддреНрддрд░ рдкреИрдЯрд░реНрди рдХрд╛ рдкреВрд░реА рддрд░рд╣ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдкреАрдЖрдИ рдореЗрдВ рдЕрднреА рднреА рдХреБрдЫ рдЦреБрд░рджрд░реЗ рдХрд┐рдирд╛рд░реЗ рд╣реИрдВред рдЗрд╕ рдореБрджреНрджреЗ рдореЗрдВ, рд╣рдордиреЗ рджреЗрдЦрд╛ рдХрд┐ рдПрдкреАрдЖрдИ рдХреЗ рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рд╕рд╛рд░ рдФрд░ рдЕрдиреБрдХреВрд▓рди рдПрдХ рдЕрдзрд┐рдХ рддрд╛рд░реНрдХрд┐рдХ рдЙрдЪреНрдЪ-рд╕реНрддрд░реАрдп рдПрдкреАрдЖрдИ рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдЪреЗрддрд╛рд╡рдиреА 1:рдПрдХ рдШрдЯрдирд╛-рд╕рдВрдЪрд╛рд▓рд┐рдд рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХрд╛ рдореБрдЦреНрдп рд▓рд╛рдн рдШрдЯрдирд╛ рдЙрддреНрдкрд╛рджрдХреЛрдВ рдФрд░ рдЙрдкрднреЛрдХреНрддрд╛рдУрдВ рдХрд╛ рдбрд┐рдХреЙрдкреНрд▓рд┐рдВрдЧ рд╣реИ, рдЬреЛ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд▓рдЪреАрд▓реА рдФрд░ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реА рдкреНрд░рдгрд╛рд▓реА рдмрдирд╛рдирд╛ рд╕рдВрднрд╡ рдмрдирд╛рддрд╛ рд╣реИред рд╕рд┐рдВрдХреНрд░реЛрдирд╕ рд╢рдмреНрджрд╛рд░реНрдереЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ "рдЕрдиреБрд░реЛрдз-рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛" рдареАрдХ рд╡рд┐рдкрд░реАрдд рд╣реИ рдЬрдм рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рджреЗрдиреЗ рд╡рд╛рд▓реЗ рдкрдХреНрд╖ рджреГрдврд╝рддрд╛ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реЛрддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ рддреЛ рд╣реА рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЪреЗрддрд╛рд╡рдиреА 2:рдпрджрд┐ рдПрдХ
рд╕рд┐рдВрдХреНрд░реЛрдирд╕ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ-рд░рд┐рд╕реНрдкрд╛рдВрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рддреЛ
рдЕрдкрд╛рдЪреЗ рдХрд╛рдлреНрдХрд╛ рдЬреИрд╕реЗ рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдЪреИрдирд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ
HTTP- рдЖрдзрд╛рд░рд┐рдд
рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдмрд╣реБрдд рд╕рд░рд▓ рдФрд░ рдЕрдзрд┐рдХ рдХреБрд╢рд▓ рд╣реИред
рд╣рд╛рд▓рд╛рдВрдХрд┐, рдРрд╕реЗ рдкрд░рд┐рджреГрд╢реНрдп рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд╣рд╛рдВ
рдХрд╛рдлреНрдХрд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ
рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЕрдиреБрд░реЛрдз-рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдордЭ рдореЗрдВ рдЖрддреА рд╣реИред рд╕рдордЭрджрд╛рд░реА рд╕реЗ рдХрд╛рдо рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рдЙрдкрдХрд░рдг рдЪреБрдиреЗрдВред
рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдЙрджрд╛рд╣рд░рдг
github.com/callistaenterprise/blog-synchronous-kafka рдкрд░ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ
рдлреЗрдбреЗрд░рд┐рдХреЛ тАв 7 рдорд╣реАрдиреЗ рдкрд╣рд▓реЗрдФрд░ рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рд╛рдЗрдмреНрд░рд┐рдб рдЬрд╝рд░реВрд░рддреЗрдВ рд╣реЛрддреА рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, 50% рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд╣рдореЗрдВ рдПрдХ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ-рд░рд┐рд╕реНрдкрд╛рдВрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдФрд░ 50% рдореЗрдВ рд╣рдореЗрдВ рдЗрд╡реЗрдВрдЯ рдореИрдиреЗрдЬрдореЗрдВрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ? рд╣рдо рдпрд╣ рдХреИрд╕реЗ рдХрд░рддреЗ рд╣реИрдВ? рд╕реНрдкреНрд░рд┐рдВрдЧ рдХрд╛рдлреНрдХрд╛ рджреНрд╡рд╛рд░рд╛ рдЖрд╡рд╢реНрдпрдХ рд╡рд┐рдиреНрдпрд╛рд╕ рдмрд╣реБрдд рднрдпрд╛рдирдХ рд▓рдЧ рд░рд╣рд╛ рд╣реИред
рдЬрд╣рд╛рдирдЬрд╝реЗрдм рдХрдпреНрдпреВрдо тАв 6 рдорд╣реАрдиреЗ рдкрд╣рд▓реЗрд╡рд╕рдВрдд рдореЗрдВ рдЕрдм рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рд╡рд┐рд╖рдп рдореЗрдВ рд╡рд┐рднрд╛рдЬрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕рдорд░реНрдерди рд╣реИред
рд╕рдВрд╕реНрдХрд░рдг 2.2 рд╕реЗ рд╢реБрд░реВ, рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдП рдЧрдП рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрдВрдЯреЗрдирд░ (рдЙрддреНрддрд░ рдХрдВрдЯреЗрдирд░) рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдпрд╛ рд╡рд┐рднрд╛рдЬрди рдХреЗ рд▓рд┐рдП рд╡рд┐рд╖рдп рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реИред
https://docs.spring.io/spring-kafka/reference/html/#replying-templatenir rozenberg тАв 8 рдорд╣реАрдиреЗ рдкрд╣рд▓реЗрд╣реИрд▓реЛ,
рдЕрдВрддрд┐рдо рдкреИрд░рд╛рдЧреНрд░рд╛рдл рдореЗрдВ, рдЖрдкрдиреЗ рд▓рд┐рдЦрд╛ рд╣реИ рдХрд┐ рдРрд╕реЗ рдкрд░рд┐рджреГрд╢реНрдп рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рдХрд╛рдлреНрдХрд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЕрдиреБрд░реЛрдз-рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ HTTP рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИред
рдХреНрдпрд╛ рдЖрдк рдРрд╕реЗ рдкрд░рд┐рджреГрд╢реНрдпреЛрдВ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рджреЗ рд╕рдХрддреЗ рд╣реИрдВ?
рдЖрдкрдХрд╛ рдзрдиреНрдпрд╡рд╛рдж
рдирд┐рд░
Janne Keskitalo nir rozenberg тАв 8 рдорд╣реАрдиреЗ рдкрд╣рд▓реЗрд╣рдо рдПрдХ рдмрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рд▓реЗрдирджреЗрди рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдкреНрд░рдгрд╛рд▓реА рдХреЛ рдХрдИ рдорд╛рдЗрдХреНрд░реЛрд╕рд░реНрд╡рд┐рд╕реЗрдЬ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВ, рдФрд░ рдореБрдЭреЗ рдПрдХ рд╕рдорд╛рди рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдЖрддреНрдореАрдпрддрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдлреНрдХрд╛ рдХреЗ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ-рд░рд┐рд╕реНрдкреЙрдиреНрд╕ рдореИрд╕реЗрдЬрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рд╡рд┐рдЪрд╛рд░ рд╣реИред рдореВрд▓ рд░реВрдк рд╕реЗ, рдХрд╛рдлреНрдХрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рдХреЙрд▓ рд╕реЗ рдПрдХ рд╣реА рд▓реЗрдирджреЗрди рдкреНрд░реЛрд╕реЗрд╕рд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рд╕рднреА рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рд░реВрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рддрдм рдПрдХ рд╕рдордп рдореЗрдВ рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдЙрдиреНрд╣реЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рд░реИрдЦрд┐рдХрддрд╛ рдХреЛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ (
https://stackoverflow.com/a/19515375/7430325 ), рдХрд╛рд░рдг рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рдФрд░ рдХреБрд╢рд▓ рдХреИрд╢рд┐рдВрдЧ рдХреА рднреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ, рд╕рдордиреНрд╡рдп рдкреНрд░рдпрд╛рд╕реЛрдВ рдХреЛ рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдХрд╛рдлреНрдХрд╛ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рдзрд╛рд░рд╛рд╡рд╛рд╣рд┐рдХ рдкрд░рд┐рд╡рд░реНрддрдирд╢реАрд▓ рдЕрд▓рдЧрд╛рд╡ рдореЛрдб рдореЗрдВ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдореБрдЭреЗ рдЕрднреА рддрдХ рд╣рдорд╛рд░реЗ рд▓реЗрди-рджреЗрди рд╢рдмреНрджрд╛рд░реНрдереЛрдВ рдХреЗ рд╡рд┐рд╡рд░рдг рдореЗрдВ рдпрд╣ рджреЗрдЦрдирд╛ рд╣реИ рдХрд┐ рдпрд╣ рдХрд╣рд╛рдВ рдХрдо рд╣реБрдЖ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рд╡рд┐рдЪрд╛рд░ рд╣реИред
@Middle_java рджреНрд╡рд╛рд░рд╛
рдЕрдиреБрд╡рд╛рджрд┐рдд