Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

avaje/avaje-inject

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Repository files navigation

Discord Build JDK EA License Maven Central javadoc

APT-based dependency injection for server-side developers - https://avaje.io/inject

Quick Start

1. Add avaje-inject as a dependency.

<dependency>
 <groupId>io.avaje</groupId>
 <artifactId>avaje-inject</artifactId>
 <version>${avaje.inject.version}</version>
</dependency>

2. Add avaje-inject-generator annotation processor as a dependency with provided scope.

<dependency>
 <groupId>io.avaje</groupId>
 <artifactId>avaje-inject-generator</artifactId>
 <version>${avaje.inject.version}</version>
 <scope>provided</scope>
</dependency>

3. Create a Bean Class annotated with @Singleton

@Singleton
public class Example {
 private DependencyClass d1;
 private DependencyClass2 d2;
 // Dependencies must be annotated with singleton,
 // or else be provided from another class annotated with @Factory
 public Example(DependencyClass d1, DependencyClass2 d2) {
 this.d1 = d1;
 this.d2 = d2;
 }
}

Example factory class:

@Factory
public class ExampleFactory {
 @Bean
 public DependencyClass2 bean() {
 return new DependencyClass2();
 }
}

4. Use BeanScope to wire and retrieve the beans and use them however you wish.

BeanScope beanScope = BeanScope.builder().build()
Example ex = beanScope.get(Example.class);

Java Module Usage

When working with Java modules you need to add a provides statement in your module-info.java with the generated class.

import io.avaje.inject.spi.InjectExtension;
module org.example {
 requires io.avaje.inject;
 // you must define the fully qualified class name of the generated classes. if you use an import statement, compilation will fail
 provides InjectExtension with org.example.ExampleModule;
}

Generated Wiring Class

The inject annotation processor determines the dependency wiring order and generates an AvajeModule class that calls all the generated DI classes.

@Generated("io.avaje.inject.generator")
@InjectModule
public final class ExampleModule implements AvajeModule {
 private Builder builder;
 @Override
 public Class<?>[] classes() {
 return new Class<?>[] {
 org.example.DependencyClass.class,
 org.example.DependencyClass2.class,
 org.example.Example.class,
 org.example.ExampleFactory.class,
 };
 }
 /**
 * Creates all the beans in order based on constructor dependencies. The beans are registered
 * into the builder along with callbacks for field/method injection, and lifecycle
 * support.
 */
 @Override
 public void build(Builder builder) {
 this.builder = builder;
 // create beans in order based on constructor dependencies
 // i.e. "provides" followed by "dependsOn"
 build_example_ExampleFactory();
 build_example_DependencyClass();
 build_example_DependencyClass2();
 build_example_Example();
 }
 @DependencyMeta(type = "org.example.ExampleFactory")
 private void build_example_ExampleFactory() {
 ExampleFactory$DI.build(builder);
 }
 @DependencyMeta(type = "org.example.DependencyClass")
 private void build_example_DependencyClass() {
 DependencyClass$DI.build(builder);
 }
 @DependencyMeta(
 type = "org.example.DependencyClass2",
 method = "org.example.ExampleFactory$DI.build_bean", // factory method
 dependsOn = {"org.example.ExampleFactory"}) //factory beans naturally depend on the factory
 private void build_example_DependencyClass2() {
 ExampleFactory$DI.build_bean(builder);
 }
 @DependencyMeta(
 type = "org.example.Example",
 dependsOn = {"org.example.DependencyClass", "org.example.DependencyClass2"})
 private void build_example_Example() {
 Example$DI.build(builder);
 }
}

Similar to Dagger

  • Uses Java annotation processing for dependency injection
  • Generates source code
  • Avoids any use of reflection or classpath scanning (so low overhead and fast startup)

Differences to Dagger

  • Specifically aimed for server-side development (rather than Android)
  • Supports "component testing" via avaje-inject-test and @InjectTest
  • Provides an API to obtain all bean instances that implement an interface
  • Lifecycle methods with @PostConstruct and @PreDestroy
  • Spring-like factory classes with @Factory and @Bean
  • Conditional Wiring based on active profiles or existing beans/properties

DI Framework comparison

Avaje Dagger Spring
@Singleton @Singleton @Component, @Service, @Repository
Provider<T> Provider<T> FactoryBean<T>
@Inject @Inject @Inject, @Autowired
@Inject @Nullable or @Inject Optional<T> @Inject @Nullable @Autowired(required=false)
@Qualifier/@Named @Qualifier/@Named @Qualifier
@AssistFactory @AssistedFactory -
@PostConstruct - @PostConstruct
@PreDestroy - @PreDestroy
@Factory and @Bean - @Configuration and @Bean
@RequiresBean and @RequiresProperty - @Conditional
@Lazy - @Lazy
@Prototype - @Scope("prototype")
@Primary - @Primary
@Secondary - @Fallback
@InjectTest - @SpringBootTest

AltStyle によって変換されたページ (->オリジナル) /