HK2: доступ к сервисам в области RunLevel из дочернего локатора - PullRequest
0 голосов
/ 18 октября 2019

Я использую Джерси в приложении Java SE. HK2 обеспечивает внедрение зависимостей для всего приложения. HK2 RunLevel службы зарегистрированы в локаторе службы приложений, который является родительским для локатора службы Jerseys.

+ application locator
|\- RunLevel capabilities
| - MyCustomService, @RunLevel(value=1)
 \
  + jersey locator
   \- jersey resource class
     \ @Inject MyCustomService

Моя проблема заключается в том, что я не могу получить доступ к службам уровня запуска из Джерси. Когда - в приведенном выше примере - ресурс джерси открыт, внедрение MyCustomService завершается неудачно:

java.lang.IllegalStateException: Не удалось найти активный контекст для org.glassfish.hk2.runlevel. RunLevel

Причина этого, по-видимому, заключается в том, что службы, стоящие за функцией RunLevel HK2, имеют видимость LOCAL : локатор джерси не может получить к ним доступ через родительский локатор. См. здесь .

Вопросы:

  • Почему службы функции уровня запуска ограничены в видимости?
  • Чтоя могу сделать, чтобы преодолеть это?

Обновление

Чтобы дать контекст для вопроса, я использую уровни выполнения в стиле "System-V".

  • Запускается приложение Java SE. По умолчанию начальный уровень запуска равен -1, целевой уровень запуска равен 3. На своем пути для успешного продолжения необходимо пройти различные этапы.
  • На уровне выполнения 1 устанавливаются подключения к зависимым внешним приложениям (база данных, memcache, брокер сообщений). и т. д.)
  • На уровне выполнения 2 запускаются ExecutorServices для фоновой обработки и HTTP-сервисов (с запущенным трикотажем). Джерси отклоняет все входящие запросы на этом уровне.
  • На уровне выполнения 3 MessageListeners присоединяются к брокеру, отправляя запросы фоновым исполнителям. Джерси принимает и обрабатывает HTTP-запросы.

Эта концепция позволяет детально контролировать доступность и длительные запросы. При закрытии приложение будет находиться на уровне выполнения 2, пока не будут выполнены ранее принятые HTTP-запросы и не завершены поставленные в очередь фоновые задачи. Тем не менее, новые задачи / запросы не принимаются. Затем, уровень выполнения 1, 0, -1, выход.

Ответы [ 2 ]

0 голосов
/ 29 октября 2019

Я решил это с помощью этого хака: я сознательно переопределяю видимость LOCAL и вставляю требуемые дескрипторы в локатор службы, в котором они отсутствуют.

public class RunLevelBridge implements Feature {
    private final Logger log = LoggerFactory.getLogger(getClass());
    private final ServiceLocator sourceLocator;

    public RunLevelBridge(ServiceLocator sourceLocator) {
        this.sourceLocator = sourceLocator;
    }

    @Override
    public boolean configure(FeatureContext context) {
        if (sourceLocator == null) {
            log.error("Unable to bridge descriptors, the source service locator cannot be null");
            return false;
        }

        InjectionManager im = InjectionManagerProvider.getInjectionManager(context);
        ServiceLocator jerseyLocator = im.getInstance(ServiceLocator.class);
        if (jerseyLocator == null) {
            log.error("Unable to bridge descriptors, the target service locator cannot be null");
            return false;
        }

        if (!sourceLocator.equals(jerseyLocator.getParent())) {
            ExtrasUtilities.bridgeServiceLocator(jerseyLocator, sourceLocator);
            log.info("Bridge from {} into {} established", sourceLocator.getName(), jerseyLocator.getName());
        }

        Filter filter;
        filter = BuilderHelper.createContractFilter(RunLevelContext.class.getName());
        sourceLocator.getDescriptors(filter).forEach(
                (descriptor) -> ServiceLocatorUtilities.addOneDescriptor(
                        jerseyLocator, 
                        descriptor, 
                        false
                )
        );
        filter = BuilderHelper.createContractFilter(RunLevelController.class.getName());
        sourceLocator.getDescriptors(filter).forEach(
                (descriptor) -> ServiceLocatorUtilities.addOneDescriptor(
                        jerseyLocator, 
                        descriptor, 
                        false
                )
        );

        log.info("Added the RunLevel feature to jersey's service locator");
        return true;
    }

}

Мост зарегистрирован в ResourceConfig:

public class ApplicationConfig extends ResourceConfig {

    public ApplicationConfig(ServiceLocator parentLocator) {

        // bridge runlevel into jersey
        register(new RunLevelBridge(parentLocator));

        // ... other stuff ...

    }
}

Я приветствую отзывы об этом неортодоксальном подходе.

0 голосов
/ 24 октября 2019

Идея с дочерними элементами и RunLevelService заключалась в том, что фактические RunLevelServices были бы тонкой службой в дочерних локаторах, которые организовывали реальные службы в родительском объекте. И что несколько «подсистем» в процессе могут иметь разные «отсеки» RunLevelService, каждый в своем собственном дочернем элементе родителя.

В этой модели вы запускаете / добавляете RunLevelService в дочерних элементах, а не в родительском. Таким образом, вы можете иметь несколько RunLevelServices на разных уровнях у разных потомков одного и того же родителя.

Похоже, у вас другой вариант использования, который может работать не полностью. Стоит рассмотреть ваш вариант использования.

...