23
23
import java .util .Iterator ;
24
24
import java .util .List ;
25
25
import java .util .Map ;
26
+ import java .util .Set ;
26
27
import java .util .concurrent .BlockingQueue ;
27
28
import java .util .concurrent .ConcurrentHashMap ;
28
29
import java .util .concurrent .Future ;
29
30
import java .util .concurrent .LinkedBlockingQueue ;
31
+ import java .util .concurrent .atomic .AtomicBoolean ;
30
32
import java .util .concurrent .atomic .AtomicInteger ;
31
33
import java .util .function .BiPredicate ;
32
34
import java .util .function .Supplier ;
55
57
import org .springframework .context .ApplicationContext ;
56
58
import org .springframework .context .ApplicationContextAware ;
57
59
import org .springframework .context .ApplicationListener ;
60
+ import org .springframework .context .SmartLifecycle ;
58
61
import org .springframework .context .event .ContextStoppedEvent ;
59
62
import org .springframework .core .log .LogAccessor ;
60
63
import org .springframework .kafka .KafkaException ;
111
114
*/
112
115
public class DefaultKafkaProducerFactory <K , V > extends KafkaResourceFactory
113
116
implements ProducerFactory <K , V >, ApplicationContextAware ,
114
- BeanNameAware , ApplicationListener <ContextStoppedEvent >, DisposableBean {
117
+ BeanNameAware , ApplicationListener <ContextStoppedEvent >, DisposableBean , SmartLifecycle {
115
118
116
119
private static final LogAccessor LOGGER = new LogAccessor (LogFactory .getLog (DefaultKafkaProducerFactory .class ));
117
120
@@ -123,6 +126,8 @@ public class DefaultKafkaProducerFactory<K, V> extends KafkaResourceFactory
123
126
124
127
private final ThreadLocal <CloseSafeProducer <K , V >> threadBoundProducers = new ThreadLocal <>();
125
128
129
+ private final Set <CloseSafeProducer <K , V >> threadBoundProducersAll = ConcurrentHashMap .newKeySet ();
130
+
126
131
private final AtomicInteger epoch = new AtomicInteger ();
127
132
128
133
private final AtomicInteger clientIdCounter = new AtomicInteger ();
@@ -131,6 +136,8 @@ public class DefaultKafkaProducerFactory<K, V> extends KafkaResourceFactory
131
136
132
137
private final List <ProducerPostProcessor <K , V >> postProcessors = new ArrayList <>();
133
138
139
+ private final AtomicBoolean running = new AtomicBoolean ();
140
+
134
141
private Supplier <Serializer <K >> keySerializerSupplier ;
135
142
136
143
private Supplier <Serializer <V >> valueSerializerSupplier ;
@@ -519,6 +526,27 @@ public void setMaxAge(Duration maxAge) {
519
526
this .maxAge = maxAge .toMillis ();
520
527
}
521
528
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
+
522
550
/**
523
551
* Copy properties of the instance and the given properties to create a new producer factory.
524
552
* <p>If the {@link org.springframework.kafka.core.DefaultKafkaProducerFactory} makes a
@@ -677,7 +705,12 @@ public void destroy() {
677
705
this .producer = null ;
678
706
}
679
707
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
+ }
681
714
}
682
715
this .cache .values ().forEach (queue -> {
683
716
CloseSafeProducer <K , V > next = queue .poll ();
@@ -691,6 +724,16 @@ public void destroy() {
691
724
next = queue .poll ();
692
725
}
693
726
});
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 ();
694
737
this .epoch .incrementAndGet ();
695
738
}
696
739
@@ -760,6 +803,7 @@ private Producer<K, V> getOrCreateThreadBoundProducer() {
760
803
CloseSafeProducer <K , V > tlProducer = this .threadBoundProducers .get ();
761
804
if (tlProducer != null && (tlProducer .closed || this .epoch .get () != tlProducer .epoch || expire (tlProducer ))) {
762
805
closeThreadBoundProducer ();
806
+ this .threadBoundProducersAll .remove (tlProducer );
763
807
tlProducer = null ;
764
808
}
765
809
if (tlProducer == null ) {
@@ -769,6 +813,7 @@ private Producer<K, V> getOrCreateThreadBoundProducer() {
769
813
listener .producerAdded (tlProducer .clientId , tlProducer );
770
814
}
771
815
this .threadBoundProducers .set (tlProducer );
816
+ this .threadBoundProducersAll .add (tlProducer );
772
817
}
773
818
return tlProducer ;
774
819
}
@@ -907,6 +952,7 @@ public void closeThreadBoundProducer() {
907
952
CloseSafeProducer <K , V > tlProducer = this .threadBoundProducers .get ();
908
953
if (tlProducer != null ) {
909
954
this .threadBoundProducers .remove ();
955
+ this .threadBoundProducersAll .remove (tlProducer );
910
956
tlProducer .closeDelegate (this .physicalCloseTimeout , this .listeners );
911
957
}
912
958
}
0 commit comments