2323import java .util .Iterator ;
2424import java .util .List ;
2525import java .util .Map ;
26+ import java .util .Set ;
2627import java .util .concurrent .BlockingQueue ;
2728import java .util .concurrent .ConcurrentHashMap ;
2829import java .util .concurrent .Future ;
2930import java .util .concurrent .LinkedBlockingQueue ;
31+ import java .util .concurrent .atomic .AtomicBoolean ;
3032import java .util .concurrent .atomic .AtomicInteger ;
3133import java .util .function .BiPredicate ;
3234import java .util .function .Supplier ;
5557import org .springframework .context .ApplicationContext ;
5658import org .springframework .context .ApplicationContextAware ;
5759import org .springframework .context .ApplicationListener ;
60+ import org .springframework .context .SmartLifecycle ;
5861import org .springframework .context .event .ContextStoppedEvent ;
5962import org .springframework .core .log .LogAccessor ;
6063import org .springframework .kafka .KafkaException ;
111114 */
112115public class DefaultKafkaProducerFactory <K , V > extends KafkaResourceFactory
113116 implements ProducerFactory <K , V >, ApplicationContextAware ,
114- BeanNameAware , ApplicationListener <ContextStoppedEvent >, DisposableBean {
117+ BeanNameAware , ApplicationListener <ContextStoppedEvent >, DisposableBean , SmartLifecycle {
115118
116119 private static final LogAccessor LOGGER = new LogAccessor (LogFactory .getLog (DefaultKafkaProducerFactory .class ));
117120
@@ -123,6 +126,8 @@ public class DefaultKafkaProducerFactory<K, V> extends KafkaResourceFactory
123126
124127 private final ThreadLocal <CloseSafeProducer <K , V >> threadBoundProducers = new ThreadLocal <>();
125128
129+ private final Set <CloseSafeProducer <K , V >> threadBoundProducersAll = ConcurrentHashMap .newKeySet ();
130+
126131 private final AtomicInteger epoch = new AtomicInteger ();
127132
128133 private final AtomicInteger clientIdCounter = new AtomicInteger ();
@@ -131,6 +136,8 @@ public class DefaultKafkaProducerFactory<K, V> extends KafkaResourceFactory
131136
132137 private final List <ProducerPostProcessor <K , V >> postProcessors = new ArrayList <>();
133138
139+ private final AtomicBoolean running = new AtomicBoolean ();
140+
134141 private Supplier <Serializer <K >> keySerializerSupplier ;
135142
136143 private Supplier <Serializer <V >> valueSerializerSupplier ;
@@ -519,6 +526,27 @@ public void setMaxAge(Duration maxAge) {
519526 this .maxAge = maxAge .toMillis ();
520527 }
521528
529+ @ Override
530+ public void start () {
531+ this .running .set (true );
532+ }
533+
534+ @ Override
535+ public void stop () {
536+ this .running .set (false );
537+ destroy ();
538+ }
539+
540+ @ Override
541+ public boolean isRunning () {
542+ return this .running .get ();
543+ }
544+
545+ @ Override
546+ public int getPhase () {
547+ return Integer .MIN_VALUE ;
548+ }
549+
522550 /**
523551 * Copy properties of the instance and the given properties to create a new producer factory.
524552 * <p>If the {@link org.springframework.kafka.core.DefaultKafkaProducerFactory} makes a
@@ -677,7 +705,12 @@ public void destroy() {
677705 this .producer = null ;
678706 }
679707 if (producerToClose != null ) {
680- producerToClose .closeDelegate (this .physicalCloseTimeout , this .listeners );
708+ try {
709+ producerToClose .closeDelegate (this .physicalCloseTimeout , this .listeners );
710+ }
711+ catch (Exception e ) {
712+ LOGGER .error (e , "Exception while closing producer" );
713+ }
681714 }
682715 this .cache .values ().forEach (queue -> {
683716 CloseSafeProducer <K , V > next = queue .poll ();
@@ -691,6 +724,16 @@ public void destroy() {
691724 next = queue .poll ();
692725 }
693726 });
727+ this .cache .clear ();
728+ this .threadBoundProducersAll .forEach (prod -> {
729+ try {
730+ prod .closeDelegate (this .physicalCloseTimeout , this .listeners );
731+ }
732+ catch (Exception e ) {
733+ LOGGER .error (e , "Exception while closing producer" );
734+ }
735+ });
736+ this .threadBoundProducersAll .clear ();
694737 this .epoch .incrementAndGet ();
695738 }
696739
@@ -760,6 +803,7 @@ private Producer<K, V> getOrCreateThreadBoundProducer() {
760803 CloseSafeProducer <K , V > tlProducer = this .threadBoundProducers .get ();
761804 if (tlProducer != null && (tlProducer .closed || this .epoch .get () != tlProducer .epoch || expire (tlProducer ))) {
762805 closeThreadBoundProducer ();
806+ this .threadBoundProducersAll .remove (tlProducer );
763807 tlProducer = null ;
764808 }
765809 if (tlProducer == null ) {
@@ -769,6 +813,7 @@ private Producer<K, V> getOrCreateThreadBoundProducer() {
769813 listener .producerAdded (tlProducer .clientId , tlProducer );
770814 }
771815 this .threadBoundProducers .set (tlProducer );
816+ this .threadBoundProducersAll .add (tlProducer );
772817 }
773818 return tlProducer ;
774819 }
@@ -907,6 +952,7 @@ public void closeThreadBoundProducer() {
907952 CloseSafeProducer <K , V > tlProducer = this .threadBoundProducers .get ();
908953 if (tlProducer != null ) {
909954 this .threadBoundProducers .remove ();
955+ this .threadBoundProducersAll .remove (tlProducer );
910956 tlProducer .closeDelegate (this .physicalCloseTimeout , this .listeners );
911957 }
912958 }
0 commit comments