Reaching State of Grace in Java Dependency Management.
Find a file
2026-08-02 14:18:41 +09:00
.idea Refactoring; change project name to Verdandi 2026-08-02 00:54:25 +09:00
build-logic Reviewed by Codex 2026-08-02 14:12:05 +09:00
dependency-injection Reviewed by Codex 2026-08-02 14:18:41 +09:00
example Reviewed by Codex 2026-08-02 14:12:05 +09:00
gradle The first Nirvana 2026-07-24 05:07:56 +09:00
.gitattributes The first Nirvana 2026-07-24 05:07:56 +09:00
.gitignore The first Nirvana 2026-07-24 05:07:56 +09:00
AGENTS.md Reviewed by Codex 2026-08-02 14:12:05 +09:00
ANNOTATION.md Reviewed by Codex 2026-08-02 14:18:41 +09:00
gradle.properties The first Nirvana 2026-07-24 05:07:56 +09:00
gradlew The first Nirvana 2026-07-24 05:07:56 +09:00
gradlew.bat The first Nirvana 2026-07-24 05:07:56 +09:00
LICENSE The first Nirvana 2026-07-24 05:07:56 +09:00
README.md Reviewed by Codex 2026-08-02 14:12:05 +09:00
settings.gradle.kts Refactoring; change project name to Verdandi 2026-08-02 00:54:25 +09:00
verdandi-2.png Refactoring; change project name to Verdandi 2026-08-02 00:54:25 +09:00
verdandi-3.png Refactoring; change project name to Verdandi 2026-08-02 00:54:25 +09:00
verdandi-4.png Refactoring; change project name to Verdandi 2026-08-02 00:54:25 +09:00
verdandi.png Refactoring; change project name to Verdandi 2026-08-02 00:54:25 +09:00

Verdandi

Lightweight, High-Performance JSR-330 Dependency Injection Framework for Modern Java

Verdandi: Lightweight Dependency Injection for Modern Java.

Reaching a State of Grace in Java Dependency Management.

Java 21+ JSR-330 License

Verdandi

Verdandi는 Java 21+ 환경을 위한 경량 jakarta.inject 기반 의존성 주입(DI) 라이브러리입니다. Fluent API와 리플렉션을 사용해 생성자·필드·메서드 주입, Singleton/Prototype 수명주기, 패키지 스캔을 제공합니다.


Key Features

  • JSR-330 (jakarta.inject) 기반: @Inject, @Singleton, @Named, @Qualifier 표준 어노테이션 지원
  • Java 21 Virtual Thread 지원: 가상 스레드(Virtual Threads)를 통한 초고속 비동기 빈 초기화 (InitMode.ASYNC) 지원
  • 다양한 주입 방식: 생성자 주입(Constructor), 필드 주입(Field), 메서드/Setter 주입(Method) 전체 지원
  • 의존성 기반 자동 등록: annotation이 없는 기본 생성자 클래스도 다른 Bean에 주입되는 경우 자동 등록
  • 다형성 타입 바인딩: 상위 클래스 및 구현 인터페이스 조회와 @Named/커스텀 qualifier 지원
  • 모호성 검증: 여러 구현체가 qualifier 없이 요청되면 AmbiguousBeanException 발생
  • Classpath 스캔: 디렉터리와 JAR 패키지 스캔 지원
  • 안전한 순환 참조 탐지: ThreadLocal 기반의 인스턴스화 체인 추적을 통해 순환 의존성 발생 시 명확한 예외 제공
  • Virtual Thread 초기화: InitMode.ASYNC, awaitReady(), close()를 통한 초기화 및 자원 관리

Quick Start

1. Dependency 설정

Gradle (build.gradle.kts):

repositories {
    maven {
        name = "Elex Repository"
        url = uri("https://artifacts.elex-project.com/repository/maven/")
    }
}
dependencies {
    implementation("jakarta.inject:jakarta.inject-api:2.0.1")
    implementation("com.elex_project:verdandi:1.0.0")
}

2. Component 정의

import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.inject.Singleton;

public interface Engine {
    void start();
}

@Singleton
@Named("electricEngine")
public class ElectricEngine implements Engine {
    @Override
    public void start() {
        System.out.println("Electric engine started silently.");
    }
}

@Singleton
public class Car {
    private final Engine engine;

    @Inject
    private EngineDiagnostics diagnostics;

    @Inject
    public Car(@Named("electricEngine") Engine engine) {
        this.engine = engine;
    }

    public void drive() {
        engine.start();
        System.out.println("Car is running!");
    }
}

// annotation이 없어도 Car의 주입 대상이면 자동 등록됩니다.
class EngineDiagnostics {
    public void check() { /* ... */ }
}

3. Container 구동 및 빈 사용

Context context = Verdandi.builder()
            .scanPackages("kr.pe.elex.example")
            .build();

// 빈(Bean) 조회 및 사용
Car car = context.getBean(Car.class);
car.drive();
Context context = Verdandi.builder()
    .scanPackages("kr.pe.elex.example")
    .initMode(InitMode.ASYNC)
    .build();

context.awaitReady();
Car car = context.getBean(Car.class);
car.drive();
context.close();

콜백 기반 초기화도 사용할 수 있습니다.

Verdandi.builder()
    .scanPackages("kr.pe.elex.example")
    .initMode(InitMode.ASYNC)
    .onInit(new InitCallback() {
        @Override
        public void onComplete(Context context) {
            context.getBean(Car.class).drive();
        }

        @Override
        public void onFailure(Throwable cause) {
            cause.printStackTrace();
        }
    })
    .build();

Manual Registration

annotation을 추가할 수 없는 클래스는 명시적으로 등록할 수 있습니다.

Context context = Verdandi.builder()
    .scanPackages("kr.pe.elex.example")
    .registerClasses(ThirdPartyService.class)
    .build();

패키지 스캔과 수동 등록이 겹치는 클래스는 중복 등록되지 않습니다.

Bean Resolution Rules

  • @Singleton Bean은 컨테이너에서 하나의 인스턴스를 공유합니다.
  • @Singleton annotation이 없는 Bean은 Prototype으로 생성됩니다.
  • annotation이 없는 클래스라도 주입 그래프에 포함되고 기본 생성자가 있으면 자동 등록됩니다.
  • 동일 타입의 후보가 여러 개면 @Named 또는 커스텀 @Qualifier를 지정해야 합니다.
  • 지정한 qualifier가 없거나 요청 타입과 호환되지 않으면 NoSuchBeanException이 발생합니다.
  • 생성자·필드·메서드 주입의 순환 참조는 CircularDependencyException으로 보고됩니다.

Advanced Features

Custom Qualifier

커스텀 퀄리파이어 어노테이션을 선언하여 동일 타입의 다중 구현체를 안전하게 구분하여 주입할 수 있습니다.

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Fast {}

@Fast
public class V8Engine implements Engine { ... }

@Singleton
public class SportsCar {
    @Inject
    @Fast
    private Engine engine; // V8Engine이 주입됨
}


Architecture Overview

Verdandi는 다음과 같은 핵심 모듈로 명확히 역할이 분리되어 설계되었습니다.

+-----------------------------------------------------------------------+
|                             Verdandi (Facade)                         |
+-----------------------------------------------------------------------+
                                   |
                                   v
+-----------------------+     +-----------------------+     +-----------------------+
|    PackageScanner     | --> |     BeanRegistry      | <-- |       Injector        |
|  (Classpath Discovery)|     |    (Metadata Store)   |     |    (Di Engine / VT)   |
+-----------------------+     +-----------------------+     +-----------------------+

  1. Verdandi (Facade): 컨테이너의 설정 및 빌드를 담당하는 Fluent Builder API.
  2. PackageScanner: 디렉터리/JAR에서 클래스를 발견하고 annotation root 및 주입 그래프의 기본 생성자 의존성을 분석.
  3. BeanRegistry: 타입별 후보 목록과 qualifier 이름을 원자적으로 관리하고 다중 후보를 보존.
  4. Injector: 스코프 전략(Singleton/Prototype) 및 순환 참조를 검증하며 인스턴스를 생성하고 주입을 실행하는 핵심 엔진.

License

This project is licensed under the Apache License 2.0.

Copyright © 2026 Elex Project. All rights reserved.

https://www.elex-project.com/