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

1

6

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.

Orthoepy answered 2/11, 2016 at 16:17 Comment(0)
D
14

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 so it is used as a factory.

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 a slow operation, so we will get it lazily thanks to the get method only when it is 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 Provider<C2> c2;
    @Inject
    C1(Provider<C2> c2) {
        this.c2 = c2;
        ...
    }
}

This will allow the container to fully create an instance of C1 first (as we don't actually need to create an instance of C2 to inject a provider of C2) once done the container will be able to create an instance of C2 from this instance of 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();
        ...
    }
}
Delighted answered 2/11, 2016 at 16:22 Comment(4)
#2 - slow is not the only reason, you may also have a need for the object injected to be created when actually needed instead of at initial injection time.Pugilism
@ThorbjørnRavnAndersen if by #2, you mean "Example for #2" it is only an example to show the idea nothing more. What you described is already mentioned in my answer it is the "optional retrieval"Delighted
That is in the quote only.Pugilism
@ThorbjørnRavnAndersen the quote is the answer, the rest only illustrates itDelighted

© 2022 - 2024 — McMap. All rights reserved.