-
Notifications
You must be signed in to change notification settings - Fork 59
Dependency Injection with Dagger
Source Folder: dagger
Tech Stack:
- Dagger
Spring Framework is a great library that comes in handy for many cases. It helps to solve many problems and lets you build a robust and more maintainable code. However, it is a little bit kind of heavy. If you intend to use Spring just for dependency injection, you may consider using other lightweight IoC frameworks like Guice or Dagger.
For example, in a serverless architecture, your functions need to boot-up as fast as possible and the speed & memory usage matters as they cost money to you.
If you search for IoC benchmarks on the internet or build your own, you will find out that the Dagger is the most suitable option when the performance is the most critical thing that you should consider. In this story, I will show how to use Dagger with an example.
You need to add the Dagger dependency to the dependency list:
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>${dagger.version}</version>
</dependency>
Then you need to configure the annotation processor:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.plugins.maven-compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>${dagger.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Dagger generates code (at compile time) about how to create objects that are to be injected when needed based on the configurations you make in your code.
During compile time, Dagger searches for @Component annotated interfaces. When it finds one, it generates a class with the same name prefixed with Dagger implementing that interface and a static create method that creates an instance of it. Those @Component annotated interfaces are the places where you need to define the injectable objects.
@Component
public interface IoCContainer {
MyService myService();
}
You just need to write an abstract method without any parameter and with a return type of your desired object. If you don't do that, Dagger won't generate any code that creates object of that type.
Note that, the class that you declare to be injectable needs @Inject annotation on top of its constructor. You'll get compiler error otherwise.
public class MyService {
@Inject
public MyService() {
...
}
...
}
You can also inject objects to injectable objects:
public class MyService {
private MyBusinessLogic businessLogic;
@Inject
public MyService(MyBusinessLogic businessLogic) {
this.businessLogic = businessLogic;
...
}
...
}
public class MyBusinessLogic {
@Inject
public MyBusinessLogic() {
}
...
}
Notice that, again I decorated the constructor of the second class with @Inject annotation. Without it, dagger won't be able to inject it.
As I said above, for each @Component annotated interface, you'll get a class with the same name prefixed with Dagger implementing that interface. For the example given above, we'll get DaggerIoCContainer class and we can create an instance of it with its create() method:
public static void main(String[] args) {
IoCContainer ioc = DaggerIoCContainer.create();
MyService myService = ioc.myService();
}
The above example shows the simplest case of injecting dependencies. But what about:
- when we need to inject an instance of an interface?
- when we need to inject a class of a third-party library that we cannot modify (Decorate its construtor with
@Inject)? - when we need to inject that needs to be configured first?
In such cases, we need to help Dagger and define how to construct objects to be injected with @Provides annotated methods.
public interface MyService2 {
...
}
public class MyService2Impl implements MyService2 {
...
@Inject
public MyServiceImpl() {
}
...
}
@Module
public class SampleDaggerModule {
@Provides
@Singleton
public static MyService2 myService2() {
return new MyService2Impl();
}
...
}
We can define how to construct objects that we need and configure them before being injected to other objects. To do so, we just need to decorate the methods that returns such objects with @Provides annotation and decorate the containing class with @Module. All @Provides annotated methods should belong to a @Module annotated class.
To make the dagger be aware of such module, we need to add it to the modules property of @Component annotation.
@Singleton
@Component(modules = SampleDaggerModule.class)
public interface IoCContainer {
...
}
- Dagger is a very lightweight dependency injection framework
- It is compatible with JSR-330 standard injection annotations.
- It doesn't support private field injection
- We need to decorate the constructor of the classes that we want to be injectable with the
@Injectannotation. - We need to write
@Moduleannotated classes with@Providesannotated methods when@Injectis not sufficient.
- Home
- JPA Specification
- JMS with Spring Boot
- JMS with Spring Boot & Apache Camel
- Caching with Spring Boot & Redis
- Netflix Eureka with Spring Boot
- Netflix Hystrix & Eureka with Redis Cache
- Netflix Zuul
- Authentication Types
- Separating Unit & Integration Tests Execution Phases with Maven
- Basic CSRF Attack Simulation & Protection
- Spring Batch
- Dagger
- Concurrency with Java
- Swagger2 with Spring Boot