Chúng tôi có cùng một trường hợp sử dụng. Như đã đề cập một trong những vấn đề chính với việc tạo lại một bean trong suốt thời gian chạy là làm thế nào để cập nhật các tài liệu tham khảo đã được tiêm. Đây là thách thức chính.
Để giải quyết vấn đề này, tôi đã sử dụng lớp AtomicReference < của Java. Thay vì tiêm trực tiếp hạt đậu, tôi đã bọc nó như một AtomicReference và sau đó tiêm nó. Bởi vì đối tượng được bao bọc bởi AtomicReference có thể được thiết lập lại một cách an toàn, tôi có thể sử dụng điều này để thay đổi đối tượng bên dưới khi phát hiện thấy thay đổi cơ sở dữ liệu. Dưới đây là ví dụ về cấu hình/cách sử dụng mẫu này:
@Configuration
public class KafkaConfiguration {
private static final String KAFKA_SERVER_LIST = "kafka.server.list";
private static AtomicReference<String> serverList;
@Resource
MyService myService;
@PostConstruct
public void init() {
serverList = new AtomicReference<>(myService.getPropertyValue(KAFKA_SERVER_LIST));
}
// Just a helper method to check if the value for the server list has changed
// Not a big fan of the static usage but needed a way to compare the old/new values
public static boolean isRefreshNeeded() {
MyService service = Registry.getApplicationContext().getBean("myService", MyService.class);
String newServerList = service.getPropertyValue(KAFKA_SERVER_LIST);
// Arguably serverList does not need to be Atomic for this usage as this is executed
// on a single thread
if (!StringUtils.equals(serverList.get(), newServerList)) {
serverList.set(newServerList);
return true;
}
return false;
}
public ProducerFactory<String, String> kafkaProducerFactory() {
Map<String, Object> configProps = new HashMap<>();
configProps.put(ProducerConfig.CLIENT_ID_CONFIG, "...");
// Here we are pulling the value for the serverList that has been set
// see the init() and isRefreshNeeded() methods above
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, serverList.get());
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
return new DefaultKafkaProducerFactory<>(configProps);
}
@Bean
@Lazy
public AtomicReference<KafkaTemplate<String, String>> kafkaTemplate() {
KafkaTemplate<String, String> template = new KafkaTemplate<>(kafkaProducerFactory());
AtomicReference<KafkaTemplate<String, String>> ref = new AtomicReference<>(template);
return ref;
}
}
Sau đó, tôi cho đậu vào nơi cần thiết, ví dụ:
public MyClass1 {
@Resource
AtomicReference<KafkaTemplate<String, String>> kafkaTemplate;
...
}
public MyClass2 {
@Resource
AtomicReference<KafkaTemplate<String, String>> kafkaTemplate;
...
}
Trong một lớp riêng biệt, tôi chạy một chuỗi lịch được bắt đầu khi ngữ cảnh ứng dụng được bắt đầu. Lớp học trông giống như thế này:
class Manager implements Runnable {
private ScheduledExecutorService scheduler;
public void start() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(this, 0, 120, TimeUnit.SECONDS);
}
public void stop() {
scheduler.shutdownNow();
}
@Override
public void run() {
try {
if (KafkaConfiguration.isRefreshNeeded()) {
AtomicReference<KafkaTemplate<String, String>> kafkaTemplate =
(AtomicReference<KafkaTemplate<String, String>>) Registry.getApplicationContext().getBean("kafkaTemplate");
// Get new instance here. This will have the new value for the server list
// that was "refreshed"
KafkaConfiguration config = new KafkaConfiguration();
// The set here replaces the wrapped objet in a thread safe manner with the new bean
// and thus all injected instances now use the newly created object
kafkaTemplate.set(config.kafkaTemplate().get());
}
} catch (Exception e){
} finally {
}
}
}
Tôi vẫn đang ở hàng rào nếu đây là điều tôi sẽ ủng hộ vì nó có mùi nhẹ. Nhưng trong sử dụng hạn chế và cẩn thận, nó cung cấp một cách tiếp cận thay thế cho trường hợp sử dụng đã nêu. Xin lưu ý rằng từ quan điểm của Kafka, ví dụ mã này sẽ để nhà sản xuất cũ mở. Trong thực tế, người ta cần phải thực hiện một cuộc gọi tuôn ra() trên nhà sản xuất cũ để đóng nó. Nhưng đó không phải là ví dụ minh họa.
thuộc tính bean được tải trong giai đoạn xử lý nhà máy Bean, và tôi không nghĩ rằng chúng tôi có thể làm được nhiều điều sau đó về tải lại đặc biệt là trong đơn, bạn sẽ phải xây dựng lại bối cảnh ứng dụng mà hạt được nạp vào, đây là một ví dụ thú vị, http://stackoverflow.com/questions/4084890/spring-replacing-the-bean-property-values-with-new-property-file-values – mariubog