Google Guice

Koziołek

     1 <a href="mailto:samp">Konfiguracja</a>
     2 <a href="mailto:samp">Wiązanie ad hoc</a>
     3 <a href="mailto:samp"></a>

# Informacje podstawowe

Google Guice[#]_ jest biblioteką realizującą wzorzec wstrzykiwania zależności (ang. Dependency Injection DI). Podstawowymi założeniami, poza tymi związanymi z DI, jest maksymalne wykorzystanie mechanizmów języka Java oraz pełne uniezależnienie kodu biznesowego od biblioteki. Realizowane jest to w dwójnasób.

  • Guice jest zgodne z JSR-330[#]_ dzięki czemu można wykorzystać tylko standardowe elementy API i swobodnie wymienić implementację.
  • Cała konfiguracja Guice odbywa się w klasach Java. Dzięki temu już na etapie kompilacji może zostać sprawdzona m.n. poprawność nazw klas czy prawidłowość powiązań.

Dodatkowo takie podejście ułatwia testowanie kodu oraz jego późniejsze utrzymanie.

# Pierwsze kroki

Przyjrzyjmy się prostemu problemowi. Nasz system reprezentowany przez klasę <samp>MySystem</samp>:

package net.programers4.guice;
 
public class MySystem {
 
    private BussinessInterface bussinessInterface;
 
    public void callBussinessInterface() {
        bussinessInterface.printMessage();
    }
}

wykorzystuje interfejs <samp>BussinessInterface</samp> wywołując jego metodę <samp>printMessage</samp>. Interfejs ten może być implementowany na wiele różnych sposobów. Przykładowo może być dostarczany jako usługa zewnętrzna (web service, RMI, etc.), implementowany w ramach naszego systemu albo być dostarczany w osobnej bibliotece.
Otwartą kwestią pozostaje powiązanie klasy implementującej ten interfejs z naszym systemem. W klasycznym, bez DI, rozwiązaniu samodzielnie stworzylibyśmy obiekt i ustawili go w naszym systemie za pomocą settera albo konstruktora. Jednakże przy dużej ilości obiektów jeżeli zajdzie konieczność zmiany implementacji to musimy też samodzielnie zmienić kod wszędzie tam gdzie wywołujemy konstruktory. To może pociągnąć za sobą konieczność kolejnych zmian w kodzie itd.
W naszym przypadku dodatkową trudność stanowi brak bezpośredniego dostępu do pola. Nie jest on możliwy bez użycia refleksji. Użyjmy zatem Guice. Na tym etapie wymagać będzie to tylko jednej zmiany w kodzie. Nowa wersja klasy <samp>MySystem</samp>:

package net.programers4.guice;
 
import javax.inject.Inject;
 
public class MySystem {
 
    @Inject
    private BussinessInterface bussinessInterface;
 
    public void callBussinessInterface() {
        bussinessInterface.printMessage();
    }
}

Adnotacja @Inject</samp">samp>@Inject</samp</a> pochodzi z JSR-330. Jeszcze szybki rzut oka na klasę zawierającą metodę <samp>main</samp>:

package net.programers4.guice;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class App {

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new MyFirstModule());
        MySystem mySystemInstance = injector.getInstance(MySystem.class);
        mySystemInstance.callBussinessInterface();
    }
}

Na początku tworzymy <samp>Injector</samp>, czyli specjalny obiekt odpowiedzialny za zarządzanie całym kontenerem DI. Następnie pobieramy z niego instancję <samp>MySystem</samp> i na koniec wywołujemy interfejs biznesowy.

Konfiguracja

Guice dzieli aplikację na moduły. Modułem jest klasa implementująca interfejs <samp>Module</samp>, ale w praktyce zamiast implementować ten interfejs rozszerza się jedną z kilku klas dostarczonych wraz z biblioteką (<samp>AbstractModule</samp>, <samp>PrivateModule</samp>). W powyższym przypadku modułem głównym jest <samp>MyFirstModule</samp>:

package net.programers4.guice;

import com.google.inject.AbstractModule;
import com.google.inject.Scopes;

public class MyFirstModule extends AbstractModule {

    /**
     * Konfiguracja modułu.
     */
    protected void configure() {
        bind(BussinessInterface.class).to(BussinessInterfaceImplA.class).in(
                Scopes.SINGLETON);
    }

}

Metoda <samp>bind</samp> zwraca obiekt zawierający informację o powiązaniu (ang. binding) interfejsu z parametru z klasą. Mapowanie interfejs-klasa odbywa się tu za pomocą metody <samp>to</samp>.
Metoda <samp>in</samp> reprezentuje [[java/Guice/Scope|zakres]], który w tym przypadku jest [[inżynieria_oprogramowania/Wzorce_Projektowe/Singleton|singletonem]]. Domyślnym zakresem w Guice jest <samp>NO_SCOPE</samp> co oznacza, że za każdym razem jeżeli należy wstrzyknąć obiekt jest tworzona nowa instancja.

Wiązanie ad hoc

Warto zauważyć, że w konfiguracji nie podajemy informacji o klasie <samp>MySystem</samp>. W przypadku klas, które pobieramy bezpośrednio i nie wiążemy ich z konkretnym interfejsem nie ma konieczności konfigurowania ich w ramach modułu. Muszą one jednak spełniać kilka warunków:

Muszą mieć nie prywatny konstruktor domyślny. Jest to równoważne z brakiem konstruktora.</li> Jeżeli nie posiadają konstruktora domyślnego to muszą mieć dokładnie jeden konstruktor oznaczony adnotacją

Metody wstrzykiwania zależności

  • 2012-01-09 20:57
  • 0 komentarzy
  • 3281 odsłon

0 komentarzy