java ee - example - Когда уничтожается бина CDI с @dependent, если вы получаете этот компонент через Provider.get()?



java-ee jboss-weld (2)

Я изо всех сил @Dependent понять эффективный жизненный цикл объекта @Dependent в обоих CDI 1.0 и CDI 1.1. Мои эксперименты до сих пор привели меня к следующим выводам:

  • Объект, @Dependent , не проксирован.
  • Метод @PreDestroy не @PreDestroy при @Dependent компонента @Dependent .
  • Provider.get() всегда создает новый экземпляр компонента @Dependent .
  • С JBoss 6 / CDI 1.0 компонент @Dependent , созданный @ApplicationScoped Provider<> @ApplicationScoped bean's Provider<> «просочился», потому что он все еще «принадлежит» Provider .
  • Я не видел никаких доказательств (пока!) @Dependent beans, просочившихся аналогичными Provider при использовании WELD 2.1.2.Final/CDI 1.1. (Хотя это может быть связано с тем, что эти конкретные @Dependent beans создаются с @Produces методов @Produces ...!)

Я вижу, что CDI 1.1 добавил метод destroy() к Instance<> , предположительно для устранения утечки памяти в CDI 1.0. Но как насчет Provider<> - он все еще течет в CDI 1.1? (И если это так, то как вы должны использовать Provider.get() ?)

В принципе, у меня есть несколько @ApplicationScoped beans / @Singleton EJB, в которые я @Inject поля I @Inject Provider , и я пытаюсь использовать Provider.get() качестве @Dependent для @Dependent @RequestScoped компонента @Dependent и @RequestScoped . Я определенно не хочу, чтобы эти бобы «принадлежали» к их полям « Provider , так как мне нужно, чтобы бобы собирались после сбора мусора:

public void updateStuff() {
    Helper helper = helperProvider.get();
    // use helper...
}

Для моего приложения CDI 1.0 я думал об исправлении утечки памяти путем «подделки» моего Provider с кодом следующим образом:

provider = new Provider<MyBean>() {
    @Override
    public MyBean get() {
        return getReferenceFor(MyBean.class);
    }
};

private <T> T getReferenceFor(Class<T> type) {
    Bean<?> bean = beanManager.resolve(beanManager.getBeans(type));
    CreationalContext<?> context = beanManager.createCreationalContext(bean);
    try {
        return (T) beanManager.getReference(bean, bean.getBeanClass(), context);
    } finally {
        // Destroy this context - which I don't want to exist anyway.
        // I only need a strong reference to a fully @Inject-ed bean!
        context.release();
    }
}

MyBean - это @Dependent bean без метода @PreDestroy который должен быть собран только при сборке мусора, когда я закончил с ним. Тем не менее, я не могу найти много информации об Provider , и поэтому не могу сказать, могу ли я вооружить какую-то бомбы замедленного действия, сделав это.

Некоторые из моих @Dependent (которые я все еще получаю через Provider.get() , btw) создаются методами @Produces . Они все еще находятся под угрозой утечки?

Может кто-нибудь мне посоветует, пожалуйста?
Благодаря,
Крис


Из документов Weld по жизненному циклу @Dependent beans:

Экземпляр зависимого компонента никогда не делится между разными клиентами или разными точками инъекции. Это строго зависимый объект другого объекта. Он создается, когда объект, к которому он принадлежит, создается и уничтожается, когда объект, к которому он принадлежит, уничтожается.

Поэтому инъекция объекта @Dependent не приведет к утечке самостоятельно, просто ничего не исправить. Создание короткоживущего контекста просто «чтобы быть в безопасности» совершенно не нужно, потому что зависимые бобы не привязаны к контексту. Что касается CDI, то после инъекции они являются обычными (сильно достижимыми) объектами Java.
Если вам нужна логика создания экземпляра, поставьте его в методе производителя, и все.


Я не тестировал вашу конструкцию, но лично, когда мне нужно искать программный компонент, я предпочитаю CDI.current().select().get() . Используя эту конструкцию, я могу подтвердить, что вы получите новый компонент @Dependent для каждого поиска. Он не привязан к провайдеру (контейнер CDI в этом случае).

Смотрите это и это . Здесь у нас есть тестовая установка Arquillian, которая развертывает сервлет на «реальном» ( или «удаленном» с использованием сервера Arquillian ) и выдает запрос HTTP GET, чтобы узнать, какие бобы производятся внутри.

Результатом является то, что как GlassFish 4.1, так и WildFly 8.2.0 будут снабжать клиентский код одним новым компонентом @Dependent для каждого поиска, и если я правильно понял ваш вопрос, то это именно то, что вы хотите. Надеюсь, поможет!





weld