Tôi đang cố gắng tạo các cá thể của bean được quản lý bằng cách sử dụng BeanManager thay vì Instance .select(). Get().Làm thế nào để tạo và hủy diệt Đậu Quản lý CDI (Weld) thông qua BeanManager?
Điều này đã được đề xuất như là một giải pháp cho một vấn đề tôi đã gặp với hạt ApplicationScoped và thu gom rác của người phụ thuộc của họ - xem CDI Application and Dependent scopes can conspire to impact garbage collection? cho nền và giải pháp được đề xuất này.
Nếu bạn sử dụng phương pháp tra cứu lập trình Instance trên một hạt ApplicationScoped, đối tượng Instance và bất kỳ bean nào bạn nhận được từ nó đều phụ thuộc vào bean ApplicationScoped, và do đó chia sẻ vòng đời của nó. Tuy nhiên, nếu bạn tạo bean với BeanManager, bạn có một handle trên bản thân Bean, và rõ ràng có thể phá hủy nó một cách rõ ràng, cái mà tôi hiểu có nghĩa là nó sẽ được GC.
cách tiếp cận hiện tại của tôi là tạo ra đậu bên trong một lớp BeanManagerUtil, và trả về một đối tượng hỗn hợp của Bean, ví dụ, và CreationalContext:
public class BeanManagerUtil {
@Inject private BeanManager beanManager;
@SuppressWarnings("unchecked")
public <T> DestructibleBeanInstance<T> getDestructibleBeanInstance(final Class<T> type,
final Annotation... qualifiers) {
DestructibleBeanInstance<T> result = null;
Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(type, qualifiers));
if (bean != null) {
CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean);
if (creationalContext != null) {
T instance = bean.create(creationalContext);
result = new DestructibleBeanInstance<T>(instance, bean, creationalContext);
}
}
return result;
}
}
public class DestructibleBeanInstance<T> {
private T instance;
private Bean<T> bean;
private CreationalContext<T> context;
public DestructibleBeanInstance(T instance, Bean<T> bean, CreationalContext<T> context) {
this.instance = instance;
this.bean = bean;
this.context = context;
}
public T getInstance() {
return instance;
}
public void destroy() {
bean.destroy(instance, context);
}
}
Từ đó, trong đoạn code gọi, tôi có thể sau đó nhận được Ví dụ thực tế, đặt nó trong một bản đồ để thu hồi sau, và sử dụng như bình thường:
private Map<Worker, DestructibleBeanInstance<Worker>> beansByTheirWorkers =
new HashMap<Worker, DestructibleBeanInstance<Worker>>();
...
DestructibleBeanInstance<Worker> destructible =
beanUtils.getDestructibleBeanInstance(Worker.class, workerBindingQualifier);
Worker worker = destructible.getInstance();
...
Khi tôi đang thực hiện với nó, tôi có thể tra cứu các wrapper phá hủy và gọi tiêu diệt() vào nó, và đậu và người phụ thuộc của nó nên được làm sạch:
DestructibleBeanInstance<JamWorker> workerBean =
beansByTheirWorkers.remove(worker);
workerBean.destroy();
worker = null;
Tuy nhiên, sau khi chạy một số công nhân và để lại JBoss của tôi (7.1.0.Alpha1-SNAPSHOT) trong vòng 20 phút hoặc lâu hơn, tôi có thể thấy GC xảy ra
2011.002: [GC
Desired survivor size 15794176 bytes, new threshold 1 (max 15)
1884205K->1568621K(3128704K), 0.0091281 secs]
Tuy nhiên, một biểu đồ jmap vẫn show các công nhân cũ và các trường hợp phụ thuộc của họ treo quanh, unGCed. Tôi đang thiếu gì?
Thông qua gỡ lỗi, tôi có thể thấy rằng trường ngữ cảnh của bean được tạo có ngữ cảnh của loại Công việc chính xác, không có không đầy đủVật và không có parentDependentInstances. Nó có một số dependInstances, như mong đợi từ các lĩnh vực trên công nhân.
Một trong các trường này trên Công nhân thực sự là một Trường hợp và khi tôi so sánh trường này với trường Công nhân được truy xuất thông qua tra cứu Sơ đồ lập trình, chúng có trang điểm CreationalContext hơi khác. Trường Instance trên Worker được tra cứu thông qua Instance có bản thân nhân viên trong undompleteInstances, trong khi trường Instance trên Worker được lấy từ BeanManager thì không. Cả hai đều có parentDependentInstances và dependsInstances giống nhau.
Điều này gợi ý với tôi rằng tôi đã không phản ánh việc truy xuất phiên bản chính xác. Điều này có thể góp phần vào việc thiếu sự hủy diệt không?
Cuối cùng, khi gỡ lỗi, tôi có thể thấy bean.destroy() được gọi trong DestructibleBeanInstance.destroy() của tôi, và điều này đi qua để ManagedBean.destroy và tôi có thể thấy các đối tượng phụ thuộc bị hủy như một phần của .release(). Tuy nhiên họ vẫn không thu gom rác!
Bất kỳ trợ giúp nào về điều này sẽ được đánh giá rất nhiều! Cảm ơn.
Cảm ơn một lần nữa, Jason. Tôi đã thực hiện các thay đổi bạn đã đề xuất nhưng vẫn không thấy bất kỳ bộ sưu tập rác nào. Tuy nhiên khi tôi chờ đợi một GC _full_, cả hai cách tiếp cận dẫn đến các đối tượng được thu thập - thành công! Đây không phải là trường hợp trên một GC đầy đủ trước đây. Nếu bạn có thời gian, vui lòng giải thích sự khác biệt giữa '.createCreationContext (null)' và '.createCreationContext (bean)'? Tôi đã nhìn thấy trước đây trong các tài liệu để viết một phần mở rộng, nhưng tôi nghĩ đó là khi phiên bản 'đậu' của loại (nếu bạn thấy những gì tôi có nghĩa là) đã không tồn tại? Cảm ơn một lần nữa vì sự giúp đỡ. –
Theo spec, nó cung cấp cho bạn một thể hiện không theo ngữ cảnh của bean, do đó không nên có bất cứ điều gì khác có liên quan đến nó bên cạnh phần mã được chạy để tạo ra nó. Tôi đã hỏi Pete Muir về một số thông tin chi tiết bổ sung, nhưng tôi chưa nghe lại. – LightGuard