0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Javaで簡単な自作DIを作成

Last updated at Posted at 2025-02-02

ここでは、SpringやJavaEE等のDIコンテナを使わずに、自作アノテーションを使って 依存性注入(DI) を行う方法を紹介します。
リフレクションを利用して、クラスのフィールドにアノテーションが付いているかをチェックし、自動でインスタンスを注入する仕組みを作ります。

1. 環境

  • java:openjdk version "21.0.5"
C:\pleiades\2024-12\java\21\bin>java -version
openjdk version "21.0.5" 2024-10-15 LTS
OpenJDK Runtime Environment Temurin-21.0.5+11 (build 21.0.5+11-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.5+11 (build 21.0.5+11-LTS, mixed mode, sharing)

C:\pleiades\2024-12\java\21\bin>

2. 作成するファイル

作成するファイルは以下となります。

No  ファイル名 説明
1 MyAutowired.java カスタムアノテーション@MyAutowired、DIを示す自作アノテーション
2 HelloService.java DI対象のクラス
3 MyController.java @MyAutowiredを使ってDIを適用するクラス
4 MyDIContainer.java 自作のDIコンテナ
5 Main.java 動作確認

3. 簡単な自作DIを作成

3.1. 自作アノテーションを作成

まず、DIの対象であることを示す@MyAutowiredアノテーションを作成します。

MyAutowired.java
package di;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)		// 実行時にアノテーションを保持
@Target(ElementType.FIELD)				// フィールドに適用
public @interface MyAutowired {
}

3.2. DI の対象となるクラス

依存関係としてインジェクトするクラスを作成します。

HelloService.java
package di;

public class HelloService {
	public void sayHello() {
		System.out.println("Hello, Custom DI!");
	}
}

このHelloServiceクラスのインスタンスを、@MyAutowiredの付いたフィールドに自動注入します。

3.3. 自作の DI コンテナ(MyDIContainer)を作成

次に、@MyAutowiredをスキャンし、対象のクラスにインスタンスを注入するMyDIContainerクラスを作成します。

MyDIContainer.java
package di;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class MyDIContainer {

	private Map<Class<?>, Object> beans = new HashMap<>();

    public MyDIContainer() {
        // 依存オブジェクトを手動で登録(実際のフレームワークでは自動スキャン)
        beans.put(HelloService.class, new HelloService());
    }

    public void injectDependencies(Object object) {
        Class<?> clazz = object.getClass();							// 渡されたオブジェクトのクラス情報を取得
        for (Field field : clazz.getDeclaredFields()) {				// クラスのフィールドを取得
            if (field.isAnnotationPresent(MyAutowired.class)) {		// フィールドに @MyAutowired があるかチェック
                Class<?> fieldType = field.getType();				// フィールドの型を取得
                Object dependency = beans.get(fieldType);			// 依存オブジェクトを beans から取得
                if (dependency != null) {
                    field.setAccessible(true);						// private フィールドでもアクセスできるようにする
                    try {
                        field.set(object, dependency);				// フィールドにインスタンスをセット
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException("Failed to inject dependency", e);
                    }
                }
            }
        }
    }
}

injectDependencies()メソッドは、オブジェクトのフィールドをスキャンし、@MyAutowiredが付いたフィールドに適切なインスタンスを注入します。

3.4. @MyAutowiredを使ってDIを適用するクラス

次に、@MyAutowiredを利用してHelloServiceを DIするクラスを作成します。

MyController.java
package di;

public class MyController {
	@MyAutowired
	private HelloService helloService;	// 自動 DI

	public void execute() {
		helloService.sayHello();		// HelloService のメソッドを実行
	}
}

通常の @Autowiredのように、@MyAutowiredHelloServiceを自動DIできます。

3.5. 動作確認のためのMainクラスを作成

最後に、MyDIContainerを使ってMyControllerのインスタンスを作成し、依存関係を注入します。

Main.java
package di;

public class Main {
	public static void main(String[] args) {
		MyDIContainer container = new MyDIContainer();		// DI コンテナを作成
		MyController controller = new MyController();	// コントローラを作成
		
		container.injectDependencies(controller);			// 依存関係を注入

		controller.execute(); 								// 実行
	}
}

4. 実行結果

Main.javaを実行すると、期待通り、MyControllerにHelloServiceが自動的にDIされ、期待通りに動作することを確認できました。

実行結果
C:\pleiades\2024-12\workspace\git\java\bin>C:\pleiades\2024-12\java\21\bin\java.exe di.Main
Hello, Custom DI!

C:\pleiades\2024-12\workspace\git\java\bin>

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?