BeanManager всегда возвращает одну и ту же ссылку

Я создаю пользовательскую область CDI и использую BeanManager чтобы получить инъекцию моего NavigationHandler пользовательский класс. Но бобы, которые он возвращает, довольно странные.

Поэтому я использую BeanManager таким образом:

public class ScreenContext implements Context
{
    private NavigationHandler getNavigationHandler()
    {
        final Set<Bean<?>> beans = m_beanManager.getBeans(NavigationHandler.class);
        final Bean<?> bean = m_beanManager.resolve(beans);

        NavigationHandler reference =
            (NavigationHandler) m_beanManager.getReference(bean, NavigationHandler.class,
                m_beanManager.createCreationalContext(bean));

        System.out.println("Found "+reference+" (hash="+reference.hashCode()+")");
        return reference;
    }
    ...
}

Я ожидаю, когда я использую свой проект с использованием двух разных браузеров, чтобы получить два разных NavigationHandler, которые определены таким образом:

@Named
@WindowScoped
public class NavigationHandler
    implements Serializable, INavigationHandlerController

Но мой отладчик возвращается true когда я проверяю reference1==reference2, Я также получаю странные хэш-коды:

Found NavigationHandler@593e785f (hash=1261587818)
Found NavigationHandler@b6d51bd (hash=1261587818)

Я не понимаю, почему хеши, используемые в toString(), отличаются, но хеш, используемый в hashCode(), одинаков.

1 ответ

Я думаю, что я выяснил причину этих двух связанных проблем, это было сложно!

m_beanManager.getReference(..) не возвращает экземпляр NavigationHandler, но прокси, который должен выбирать и действовать как правильный NavigationHandler среди существующих в контексте области.

Ссылка для понимания концепции Proxy / Context / BeanManager: https://developer.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies

Так что мой getNavigationHandler() метод не подходит для работы: мой пул, который вызывает этот метод, будет содержать прокси NavigationHandler вместо NavigationHandlers. Потому что мой бассейн не @InjectВ поле ed прокси не будет автоматически обновляться с помощью CDI, поэтому возвращаемая ссылка всегда совпадает с последней из контекста, активно используемого прокси.

По той же причине в этом выводе:

Found NavigationHandler@593e785f (hash=1261587818)
Found NavigationHandler@b6d51bd (hash=1261587818)

В одном случае я получаю хэш NavigationHandler экземпляр, а в другом случае я получаю хэш NavigationHandlerпрокси. И все же я не знаю, кто из них какой. Я готов поверить, что toString() прокси используется, так как beanManager.getReference(..) должен каждый раз обслуживать новый прокси, а hashCode должен быть практически уникальным для каждого экземпляра объекта.

Ссылка, в которой говорится, что хэш-код каждого экземпляра является уникальным хеш-кодом и не может изменяться со временем: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

Так что правильный способ реализации getNavigationHandler() является:

private getNavigationHandlergetgetNavigationHandler()
{
    final Set<Bean<?>> beans = m_beanManager.getBeans(getNavigationHandler.class);
    final Bean<?> bean = m_beanManager.resolve(beans);

    /* Works : pure reference (not proxied) */
    Class<? extends Annotation> scopeType = bean.getScope();
    Context context = m_beanManager.getContext(scopeType);
    CreationalContext<?> creationalContext = m_beanManager.createCreationalContext(bean);
    // Casts below are necessary since inheritence does not work for templates
    getNavigationHandler reference =
        context.get((Bean<NavigationHandler>) bean, (CreationalContext<NavigationHandler>) creationalContext);

    return reference;
}

Ссылка, которая объясняет разницу между beanManager.getReference(..) а также beanManager.getContext(..).get(..): Канонический способ получения экземпляра управляемого компонента CDI: BeanManager#getReference() vs Context#get()

Другие вопросы по тегам