Szukaj…


Podstawowa iniekcja zależności za pomocą HK2 Jersey

Jersey (2) wykorzystuje HK2 jako swój system wstrzykiwania zależności (DI). Możemy korzystać z innych systemów wstrzykiwania, ale jego infrastruktura jest zbudowana z HK2 i pozwala nam również używać go w naszych aplikacjach.

Konfiguracja prostego wstrzykiwania zależności za pomocą Jersey zajmuje tylko kilka wierszy kodu. Powiedzmy na przykład, że mamy usługę, którą chcielibyśmy wprowadzić do naszych zasobów.

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

I chcemy wprowadzić tę usługę do zasobu Jersey

@Path("greeting")
public class GreetingResource {

    @Inject
    public GreetingService greetingService;

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

Aby zastrzyk zadziałał, potrzebujemy tylko prostej konfiguracji

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

Mówimy tutaj, że chcemy powiązać GreetingService z systemem wstrzykiwania i reklamować ją jako wstrzykiwalną przez tę samą klasę. Ostatnie zdanie oznacza, że możemy wstrzyknąć je tylko jako GreetingService i (prawdopodobnie oczywiście) nie przez żadną inną klasę. Jak zobaczycie później, można to zmienić.

Otóż to. To wszystko czego potrzebujesz. Jeśli nie znasz tej konfiguracji ResourceConfig (być może używasz pliku web.xml), zapoznaj się z tematem Konfigurowanie JAX-RS w Jersey w dokumentacji SO.


Uwaga: powyższy zastrzyk to wstrzyknięcie w pole, w którym usługa jest wstrzykiwana w pole zasobu. Innym rodzajem wstrzykiwania jest wstrzykiwanie do konstruktora, w którym usługa jest wstrzykiwana do konstruktora

private final GreetingService greetingService;

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

Jest to prawdopodobnie preferowany sposób postępowania w przeciwieństwie do wstrzykiwania w terenie, ponieważ ułatwia testowanie zasobów. Wtrysk konstruktora nie wymaga żadnej innej konfiguracji.


Ok, powiedzmy teraz, że zamiast klasy GreetingService jest interfejsem i mamy jego implementację (co jest bardzo powszechne). Aby to skonfigurować, użyjemy następującej składni w powyższej metodzie configure

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

Odczytuje się to jako „bind NiceGreetingService i reklamuj go jako GreetingService ”. Oznacza to, że możemy użyć dokładnie tego samego kodu w powyższym GreetingResource , ponieważ reklamujemy umowę jako GreetingService a nie NiceGreetingService . Ale rzeczywistą implementacją po wstrzyknięciu będzie NiceGreetingService .

A co z zakresem. Jeśli kiedykolwiek pracowałeś z jakimkolwiek szkieletem wstrzykiwania, zetknąłeś się z pojęciem zakresu, który określa żywotność usługi. Być może słyszałeś o „Zakresie żądania”, w którym usługa jest dostępna tylko przez cały okres żądania. Lub „Zakres Singleton”, w którym jest tylko jedna instancja usługi. Możemy skonfigurować te zakresy również przy użyciu następującej składni.

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

Domyślnym zakresem jest PerLookup , co oznacza, że za każdym razem, gdy ta usługa jest wymagana, tworzony będzie nowy. W powyższym przykładzie za pomocą RequestScoped zostanie utworzona nowa usługa dla pojedynczego żądania. To może, ale nie musi być takie samo jak PerLookup , w zależności od tego, ile miejsc próbujemy wprowadzić. Być może próbujemy wstrzyknąć go do filtra i do zasobu. Gdyby to był PerLookup , dla każdego żądania zostałyby utworzone dwie instancje. W tym przypadku chcemy tylko jednego.

Pozostałe dwa dostępne zakresy to Singleton (utworzono tylko jedno wystąpienie) i Immediate (jak Singleton ), ale jest on tworzony podczas uruchamiania (podczas gdy w Singleton nie jest tworzony aż do pierwszego żądania).

Oprócz klas wiążących moglibyśmy również użyć instancji. To dałoby nam domyślny singleton, więc nie musimy używać składni in .

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

Co jeśli mamy skomplikowaną logikę tworzenia lub potrzebujemy informacji o kontekście żądania dla usługi. W tym przypadku są Factory . Większość rzeczy, które możemy wstrzyknąć do naszych zasobów na Jersey, możemy również wstrzyknąć do Factory . Weź na przykład

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 */
    }
}

Tutaj mamy fabrykę, która pobiera informacje o UriInfo z UriInfo , w tym przypadku parametry zapytania, i tworzymy z niego GreetingService . Aby go skonfigurować, używamy następującej składni

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

Otóż to. To tylko podstawy. Jest jeszcze wiele rzeczy do zrobienia dla HK i Jersey.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow