1. Preamble
1.1 Key-value pairs in Guice
-
The previous blog, "Google Guice 1: How to Implement Dependency Injection" , explained how to use Guice to implement dependency injection
-
Now, turning our attention back
EmailModule
, it inheritsAbstractModule
, overridesconfigure()
the method -
In the configure() method, by
bind().to()
bindingEmailService
the interface to a concrete implementation classQQEmailService
public class EmailModule extends AbstractModule { @Override protected void configure() { bind(EmailService.class).to(QQEmailService.class); } }
-
When an application needs an instance of the EmailService type, Guice will automatically provide a QQEmailService instance
-
bind().to()
This syntax is like defining a key-value pair,Key<EmailService>
→ \rightarrow→Provider<EmailService>
-
The interface
Provider<T>
is defined as follows, whereget()
the method is responsible for providing an instance of Tinterface Provider<T> { /** Provides an instance of T.**/ T get(); }
-
Provider<EmailService>
The pseudocode is as follows, providing a singleton EmailService instanceclass EmailServiceProvider implements Provider<EmailService> { private static final EmailService instance = new QQEmailService(); @Override public EmailService get() { return instance; } }
1.2 key-value pair → \rightarrow→ Guice map
-
These key-value pairs form a Guice map. Among them, Key can be used
Key.get()
to buildKey<EmailService> emailService = Key.get(EmailService.class);
-
In Guice, obtaining instances explicitly or implicitly actually obtains bound objects from the Guice map
- Explicitly obtain the instance:
injector.getInstance(EmailClient.class)
, explicitly obtain the EmailClient instance// 等价于如下代码 injector.getInstance(Key.get(EmailClient.class)); // getInstance()的核心伪代码如下 public EmailClient getInstance(Key<EmailClient> key) { Provider<EmailClient> provider = guiceMap.get(key); // key为Key<EmailClient> return provider.get(); }
- Obtaining an instance implicitly: When obtaining an instance of EmailClient explicitly, you need to obtain an instance of EmailService implicitly
// 对应的核心伪代码: Provider<EmailService> provider = guiceMap.get(Key.get(EmailService.class)); // key为Key<EmailService> return provider.get();
- Explicitly obtain the instance:
2. Guice is a map
- Through the previous study, it is not difficult to find that: Guice implements object management through map. It can be said that
Guice is a map
it is GuiceMental Model
: - Mental Model: mental model? mental model? In short, it is the modeling idea of Guice
- The two important links of using Guice are also around the map
- Configuration: Configure Guice map in Guice module, or use
Just-In-Time
bindings to automatically create key-value mappings for objects - Injection: When the application needs it, Guice can create and retrieve objects from the map, thereby implementing dependency injection
- Configuration: Configure Guice map in Guice module, or use
- Just-In-Time bindings, referred to as JIT bindings, also known as
implicit bindings
implicit binding
2.1 Configuration
-
The official explanation of the Guice module:
A Guice module is a unit of configuration logic that adds things into the Guice map.
Guice module is a configuration logic unit that can add things (key-value pairs, also called binding) to Guice map -
In Guice module, you can use Guice DSL (Domain Specific Language) to configure Guice map
-
There are mainly the following DSLs (among them, the value part uses lambda expressions):
Guice DSL syntax Mental model describe bind(key).toInstance(value)
map.put(key, () -> value)
instance binding, the binding between instance object and key bind(key).to(anotherKey)
map.put(key, map.get(anotherKey))
linked binding, the binding relationship is like a chain, interlocking @Provides Foo provideFoo() {...}
map.put(Key.get(Foo.class), module::provideFoo)
Provider method binding, use @Provides
to identify a method, and define the object creation logic in the methodbind(key).toProvider(provider)
map.put(key, provider)
Provider binding, when the provider method binding becomes more and more complex, you can consider creating an independent Provider class to define the creation logic of the object -
In "Google Guice 1: How to Implement Dependency Injection" , instance binding is used,
EmailService
-->() -> qqEmailService
bind(EmailService.class).to(QQEmailService.class);
2.2 Injection
- The creation of objects depends on other objects. You do not need to actively obtain these objects (dependency) from the Guice map, but declare them directly
you need something
, and Guice will automatically inject these objects. - In Guice, the way to declare that the current class or method depends on other objects is as follows:
- Use
@Inject
annotations to identify constructors, fields, and setter methodsclass Foo { private Database database; @Inject Foo(Database database) { // We need a database, from somewhere this.database = database; } }
@Provides
The identified method, for which parameters are passed in@Provides Database provideDatabase(@DatabasePath String databasePath) { // 在创建Databas前,需要注入 @DatabasePath 标识的String实例 return new Database(databasePath); }
- Use
- PS : From the above example, we can see that dependency injection not only occurs in dependent class, but also in Guice module
3. Summary
- Guice implements several key points of dependency injection:
- First, define the creation logic of the object in the form of key-value pairs and put it into the Guice map
- Secondly, declare that dependency injection is required here by passing
@Inject
or identifying the input parameters of the method@Provides
- Finally, when obtaining an instance object (dependent obeject) that requires dependency injection, Guice Injector obtains the object (dependency) from the Guice map and injects it according to the dependency relationship, thereby completing the creation and initialization of the dependent obeject
- Throughout the process, Guice is a map, which stores the object creation logic and is the entire Guice
Mental Model