Джерси и HK2 ServiceLocator

Я пытаюсь инициализировать некоторые компоненты в моем приложении Джерси в конструкторе приложения (вещь, которая наследуется от ResourceConfig). Это выглядит так

public Application(@Context ServletContext context,
                   @Context ServiceLocator locator)...

Когда я пытаюсь использовать локатор в любой момент, я по-прежнему не могу создавать экземпляры вещей, которые я зарегистрировал в AbstractBinder, используя метод locator.create(MyThing.class).

Я уверен, что они правильно связаны, потому что они правильно вводятся в мои классы ресурсов через аннотацию поля @inject.

Разница в том, что платформа Jersey/HK2 создает экземпляры моих классов ресурсов (как и ожидалось, поскольку они находятся в моем пути сканирования пакетов), но я не могу использовать ServiceLocator через код.

Моя конечная цель - внедрить другие классы без трикотажа, когда они имеют атрибут @Inject, например. У меня есть рабочий класс, который нужно внедрить с настроенным уровнем доступа к базе данных. я хочу сказать

locator.Create(AWorker.class) 

и впрыснуть его.

Как мне получить настоящий ServiceLocator, который будет внедрять все, что я уже зарегистрировал/связал с моим Binder? (Или я должен использовать что-то другое, кроме ServiceLocator?)


person Bill    schedule 15.01.2014    source источник
comment
Я бы сказал, что вы не можете в полной мере использовать hk2 в Application. Приложение предоставляет информацию о том, как настроить Джерси. Он также должен информировать о вашем переплете hk2, связанном с Джерси. Пока эта привязка не выполнена, она недоступна через сервисный локатор.   -  person Rafael Winterhalter    schedule 16.01.2014
comment
Я регистрирую свою подшивку, прежде чем пытаться получить доступ к локатору. До сих пор не знаю, что мне делать =D   -  person Bill    schedule 16.01.2014
comment
Вы уверены, что биндер не только регистрируется, но и привязывает свои экземпляры?   -  person Rafael Winterhalter    schedule 16.01.2014
comment
Я не понимаю вопроса, но мой биндер связывает(Concrete.Class).to(Interface.class) в методе configure()   -  person Bill    schedule 16.01.2014
comment
Использование locator.create не требует, чтобы создаваемая вещь была зарегистрирована в HK2. Он попытается продолжить и создать экземпляр данного класса. Кроме того, MyThing.class НЕ будет управляться HK2, и поэтому НЕ будет доступен для дальнейшего внедрения в другие вещи. Если класс MyThing.class использует внедрение конструктора, то службы, необходимые для конструктора, конечно же, должны быть найдены в ServiceLocator. Возможно, вам следует опубликовать исключение, которое вы получаете от locator.create(MyThing.class), и, возможно, соответствующие части кода для MyThing.class.   -  person jwells131313    schedule 16.01.2014


Ответы (2)


Как вы запускаете свой контейнер? Если вы используете ApplicationHandler, вы можете просто вызвать: handler.getServiceLocator(). Действительно, ServiceLocator — это то, что вы хотите использовать для доступа к своим зависимостям.

Если вы запускаете сервлет, я обнаружил, что лучший способ получить доступ к локатору службы — установить функцию Джерси в моем классе запуска:

    private static final class LocatorSetFeature implements Feature {

    private final ServiceLocator scopedLocator;

    @Inject
    private LocatorSetFeature(ServiceLocator scopedLocator) {
        this.scopedLocator = scopedLocator;
    }

    @Override
    public boolean configure(FeatureContext context) {
        locator = this.scopedLocator; // this would set our member locator variable
        return true;
    }
}

Эта функция будет просто зарегистрирована в нашей конфигурации ресурса с помощью config.register(new LocatorSetFeature()).

Было бы важно связать запуск других компонентов на основе жизненного цикла вашего контейнера, так что это все еще кажется немного хакерским. Вы можете добавить эти классы в качестве зависимостей первого класса в контейнере HK2 и просто внедрить соответствующие зависимости в свои сторонние классы (например, с помощью Binder).

person Zack    schedule 24.02.2014
comment
Код, который вы включили, не компилируется: locator = scopedLocator не компилируется, так как локатор не был определен, где эта переменная? Пожалуйста, укажите исправление. - person PeterS; 03.06.2016

Я собираюсь предположить, что вы запускаете сервлет и у вас есть класс, расширяющий org.glassfish.jersey.server.ResourceConfig, и ваши привязки правильно зарегистрированы (например, с использованием Binder и registerInstances). Если затем вы хотите получить доступ к ServiceLocator для выполнения дополнительной инициализации, у вас есть два варианта:

Один из подходов — зарегистрировать ContainerLifecycleListener (как показано здесь в этом посте):

// In Application extends ResourceConfig constructor
register(new ContainerLifecycleListener() {

        @Override
        public void onStartup(final Container container) {
            // access the ServiceLocator here
            final ServiceLocator serviceLocator = container.getApplicationHandler().getInjectionManager().getInstance(ServiceLocator.class);

            // Perform whatever with serviceLocator
        }

        @Override
        public void onReload(final Container container) {
            /* ... */}

        @Override
        public void onShutdown(final Container container) {
            /* ... */}
    });

Второй подход заключается в использовании Feature, который также может быть обнаружен автоматически с помощью @Provider:

@Provider
public final class StartupListener implements Feature {

    private final ServiceLocator sl;

    @Inject
    public ProvisionStartupListener(final ServiceLocator sl) {
        this.sl = sl;
    }

    @Override
    public boolean configure(final FeatureContext context) {
        // Perform whatever action with serviceLocator
        return true;
    }
person sfiss    schedule 20.03.2019