Поиск…


Базовая инъекция зависимостей с использованием HK2 Джерси

Джерси (2) использует HK2 как систему впрыскивания зависимостей (DI). Мы можем использовать другие системы впрыска, но его инфраструктура построена с помощью HK2 и позволяет нам также использовать ее в наших приложениях.

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

public class GreetingService {
    public String getGreeting(String name) {
        return "Hello " + name + "!";
    }
}

И мы хотим внедрить эту услугу в ресурс Джерси

@Path("greeting")
public class GreetingResource {

    @Inject
    public GreetingService greetingService;

    @GET
    public String get(@QueryParam("name") String name) {
        return this.greetingService.getGreeting(name);
    }
}

Для того, чтобы инъекция работала, нам нужна простая конфигурация

@ApplicationPath("/api")
public class AppConfig extends ResourceConfig {
    public AppConfig() {
        register(GreetingResource.class);
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bindAsContract(GreetingService.class);
            }
        });
    }
}

Здесь мы говорим, что хотим привязать GreetingService к системе инъекций и объявить ее как инъекционную для того же класса. Что означает последнее утверждение, так это то, что мы можем вводить его только как GreetingService и (возможно, очевидно) не каким-либо другим классом. Как вы увидите позже, это можно изменить.

Вот и все. Это все, что вам нужно. Если вы не знакомы с этой конфигурацией ResourceConfig (возможно, вы используете web.xml), просьба ознакомиться с настройкой JAX-RS в теме Джерси в SO Docs.


Примечание: инъекция выше - инъекция поля, где услуга вводится в поле ресурса. Другим типом инъекции является инъекция конструктора, где услуга вводится в конструктор

private final GreetingService greetingService;

@Inject   
public GreetingResource(GreetingService greetingService) {
     this.greetingService = greetingService;
}

Вероятно, это предпочтительный вариант, в отличие от полевой инъекции, поскольку он облегчает модульный тест. Инъекция конструктора не требует никакой другой конфигурации.


Ok теперь позволяет сказать, что вместо класса GreetingService является интерфейсом, и у нас есть его реализация (что очень распространено). Чтобы настроить это, мы использовали бы следующий синтаксис в приведенном выше методе configure

@Override
protected void configure() {
    bind(NiceGreetingService.class).to(GreetingService.class);
}

Это читается как «связывать NiceGreetingService и рекламировать его как GreetingService ». Это означает, что мы можем использовать тот же самый код в GreetingResource выше, потому что мы рекламируем контракт как GreetingService а не NiceGreetingService . Но фактическая реализация при введении будет NiceGreetingService .

Теперь о сфере. Если вы когда-либо работали с любой инфраструктурой инъекций, вы столкнулись с концепцией сферы действия, которая определяет срок службы службы. Возможно, вы слышали о «области запроса», где услуга жива только для жизни запроса. Или «Singleton Scope», где есть только один экземпляр службы. Мы также можем настроить эти области применения, используя следующий синтаксис.

@Override
protected void configure() {
    bind(NiceGreetingService.class)
            .to(GreetingService.class)
            .in(RequestScoped.class);
}

Область по умолчанию - PerLookup , что означает, что каждый раз, когда запрашивается эта услуга, создается новая. В примере выше, используя RequestScoped , новая служба будет создана для одного запроса. Это может быть или не быть таким же, как PerLookup , в зависимости от того, сколько мест мы пытаемся ввести. Возможно, мы попытаемся ввести его в фильтр и в ресурс. Если это PerLookup , то для каждого запроса будут созданы два экземпляра. В этом случае мы хотим только одного.

Доступны две другие области: Singleton (только один экземпляр создан) и Immediate (например, Singleton ), но создается при запуске (тогда как с Singleton он не создается до первого запроса).

Помимо связывания классов, мы могли бы просто использовать экземпляр. Это даст нам стандартный синглтон, поэтому нам не нужно использовать синтаксис in .

@Override
protected void configure() {
    bind(new NiceGreetingService())
            .to(GreetingService.class);
}

Что делать, если у нас есть сложная логика создания или нужна информация о запросе запроса для службы. В этом случае есть Factory s. Большинство вещей, которые мы можем вводить в наши ресурсы в Джерси, мы также можем вводить в Factory . Возьмем например

public class GreetingServiceFactory implements Factory<GreetingService> {
    
    @Context
    UriInfo uriInfo;
    
    @Override
    public GreetingService provide() {
        return new GreetingService(
                uriInfo.getQueryParameters().getFirst("name"));
    }
    
    @Override
    public void dispose(GreetingService service) {
        /* noop */
    }
}

Здесь у нас есть фабрика, которая получает информацию запроса от UriInfo , в этом случае параметры запроса, и мы создаем GreetingService из нее. Чтобы настроить его, мы используем следующий синтаксис

@Override
protected void configure() {
    bindFactory(GreetingServiceFactory.class)
            .to(GreetingService.class)
            .in(RequestScoped.class);
}

Вот и все. Это всего лишь основы. Есть еще много вещей, которые делают HK и Джерси.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow