@Inject어노테이션을 만들어 DI 하기

2023. 2. 28. 18:58카테고리 없음

1. @Inject 어노테이션을 만들기 

package hello.hellospring.di;

import java.lang.annotation.*;


@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {


}

2.car 클래스에  carPosition 필드에 @Inject어노테이션 붙이기 

package hello.hellospring.di;

public class Car {
    public  CarName carName;
    @Inject
    private  CarPosition carPosition;

    public CarName getCarName() {
        return carName;
    }

    public CarPosition getCarPosition() {
        return carPosition;
    }

    @Override
    public String toString() {
        return "Car{" +
                "carName=" + carName +
                ", carPosition=" + carPosition +
                '}';
    }
}

 

package hello.hellospring.di;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Objects;

public class RefectionEx {
    public static <T> T getObject(Class<T> clazz) {
        // 해당 클래스 타입의 인스턴스 생성 및 대입
        T instance = createInstance(clazz);

        // 해당 인스턴스가 가지고 있는 필드를 하나씩 꺼낸다.
        Arrays.stream(instance.getClass().getDeclaredFields())
                .forEach(field -> {

                    // 해당 필드에 @Inject 어노테이션이 붙어있는지 확인한다.
                    if (!Objects.isNull(field.getAnnotation(Inject.class))) {
                        try {
                            // private 인 경우를 대비해서 true 로 설정
                            field.setAccessible(true);

                            // 위에서 만든 인스턴스 객체의 해당 필드에 필드 인스턴스를 생성해서 대입(set)한다.
                            field.set(instance, createInstance(field.getType()));
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }
                    }
                });

        // 인스턴스를 반환한다.
        return instance;
    }

    // 클래스 타입을 받고 해당 클래스 타입의 인스턴스 객체를 생성해서 반환
    private static <T> T createInstance(Class<T> clazz) {
        try {
            return clazz.getConstructor().newInstance();
        } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

검증

package hello.hellospring.di;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.*;
class CarTest {
    @Test
    void  reflectionTest(){
        Car car = RefectionEx.getObject(Car.class);
        System.out.println(car);
        assertAll(
                () -> assertThat(car).isNotNull(),
                () -> assertThat(car.getCarName()).isNull(),
                () -> assertThat(car.getCarPosition()).isNotNull()
        );

    }

}

getObject() 메서드로 인스턴스를 생성 시, 해당 인스턴스와 그 인스턴스의 필드 중 @Inject 어노테이션이 붙은 것까지 인스턴스 주입이 되어야 한다. 

[자바, Java] 리플렉션 (Reflection) - 리플렉션의 개념 및 사용법 | Abel’s Development Blog (tjdtls690.github.io)