diligent diligent - 1 month ago 6
Java Question

What's the difference between Inject and Provider in JSR-330

all

I don't know what's the difference between Inject and Provider in JSR-330.
I am using google guice, and everyday using

@Inject
, and I know in JSR-330, it has
Provider<T>
.

My question is


  1. what's the meaning of
    Provider<T>
    ?

  2. when can when user
    Provider<T>
    ?

  3. what's the difference with
    @Inject
    ?



Thanks in advance.

Answer

Everything is already explained into the javadoc, I quote:

Compared to injecting T directly (implicitly using @Inject only), injecting Provider<T> enables:

  1. retrieving multiple instances.
  2. lazy or optional retrieval of an instance.
  3. breaking circular dependencies.
  4. abstracting scope so you can look up an instance in a smaller scope from an instance in a containing scope.

Example for #1:

Here you get several instances of Seat from the same provider

class Car {
    @Inject 
    Car(Provider<Seat> seatProvider) {
        Seat driver = seatProvider.get();
        Seat passenger = seatProvider.get();
        ...
    }
}

Example for #2:

Here you use a provider to avoid creating directly the instance of the class MyClassLongToCreate as we know that it is slow, so we will get it lazily thanks to the get method only when needed.

class MyClass {
    @Inject
    private Provider<MyClassLongToCreate> lazy;
    ...
}

Example for #3:

Here is a circular dependency that cannot be solved easily by the container such that some containers could just throw an exception as they don't know how to solve it by their own.

class C1 {
    private final C2 c2;
    @Inject
    C1(C2 c2) {
        this.c2 = c2;
        ...
    }
}

class C2 {
    private final C1 c1;
    @Inject
    C2(C1 c1) {
        this.c1 = c1;
        ...
    }
}

To fix it we use a Provider on at least one of the constructors to break the circular dependency as next:

class C1 {
    private final C2 c2;
    @Inject
    C1(Provider<C2> c2) {
        this.c2 = c2.get();
        ...
    }
}

This will make the container create first C2 through the get call then it will be able to finish on creating C1.

Example for #4:

Here you have a class C2 that is scoped to the session which depends on C1 that itslef scoped to the request, we use a provider to allow us to get the instance of C1 corresponding to the current request as it will change from one request to another.

@RequestScoped
public class C1 {
    ...  
}

@SessionScoped
public class C2 {
    @Inject
    private Provider<C1> provider;
    ...
    public void doSomething() {
        // Get the instance corresponding to the current request
        C1 c1 = provider.get();
        ...
    }
}