Ioc container, di practice
ioc 컨테이너와 di 구현 연습
UserService.java
class UserService {
private final Logger logger;
public UserService(Logger logger) {
this.logger = logger;
}
public String getUser() {
logger.log("Getting user...");
return "{ id: 1, name: 'John Doe' }";
}
}
Logger.java
class Logger {
public void log(String message) {
System.out.println("[LOG]: " + message);
}
}
Main.java
public class Main {
public static void main(String[] args) {
DIContainer container = new DIContainer();
// 의존성 등록.
// 의존성을 해결할 때 사용할 클래스를 등록한다.
container.register("Logger", Logger.class);
container.register("UserService", UserService.class);
// 의존성 해결
// 의존성을 해결할 때 사용할 객체를 만들고, 반환한다.
// 이미 객체가 만들어진 경우, 재생성하지 않는다.
// 객체를 생성할 때, 생성자에 필요한 매개변수를 스스로 해결한다.
UserService userService = (UserService) container.resolve("UserService");
System.out.println(userService.getUser());
}
}
DIContainer.java
실제 객체를 저장하기 위해서는 Map<String, Object>를 사용해야합니다.
클래스 등록을 저장하는 맵과, 생성된 객체를 저장하는 맵이 필요합니다.
싱글턴 개념을 적용하여 인스턴스를 재사용해야합니다.
리플랙션을 사용해야합니다.
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class DIContainer {
private final Map<String, Class<?>> classMapper; // 클래스 등록을 저장하는 맵
private final Map<String, Object> instanceMap; // 생성된 객체를 저장하는 맵
public DIContainer() {
classMapper = new HashMap<>();
instanceMap = new HashMap<>();
}
public void register(String name, Class<?> targetClass) {
classMapper.put(name, targetClass);
}
public Object resolve(String name) {
// 1. 이미 인스턴스가 있으면 그대로 반환 (싱글턴 개념 적용)
if (instanceMap.containsKey(name)) {
return instanceMap.get(name);
}
// 2. 등록된 클래스 정보를 가져옴
Class<?> targetClass = classMapper.get(name);
if (targetClass == null) {
throw new IllegalArgumentException("No registered class for name: " + name);
}
try {
// 3. 생성자 정보를 가져옴
Constructor<?>[] constructors = targetClass.getConstructors();
// 4. 기본 생성자가 있는 경우
if (constructors.length == 0) {
Object instance = targetClass.getDeclaredConstructor().newInstance();
instanceMap.put(name, instance);
return instance;
}
// 5. 첫 번째 생성자를 사용하여 의존성 주입 (DI)
Constructor<?> constructor = constructors[0]; // 첫 번째 생성자 선택
Class<?>[] paramTypes = constructor.getParameterTypes();
Object[] dependencies = new Object[paramTypes.length];
// 6. 생성자 파라미터를 순회하며 필요한 의존성을 해결
for (int i = 0; i < paramTypes.length; i++) {
dependencies[i] = resolve(paramTypes[i].getSimpleName()); // 재귀적으로 의존성 해결
}
// 7. 인스턴스 생성 후 저장
Object instance = constructor.newInstance(dependencies);
instanceMap.put(name, instance);
return instance;
} catch (Exception e) {
throw new RuntimeException("Failed to create instance for: " + name, e);
}
}
}
Last updated