BeanTypeMatchingService.java
package sprout.beans.matching;
import sprout.beans.BeanDefinition;
import java.util.*;
/**
* 빈 타입 매칭 서비스
* 타입을 기반으로 빈을 찾고 매칭하는 로직을 담당
*/
public class BeanTypeMatchingService {
private final Map<String, BeanDefinition> beanDefinitions;
private final Map<String, Object> singletons;
public BeanTypeMatchingService(Map<String, BeanDefinition> beanDefinitions, Map<String, Object> singletons) {
this.beanDefinitions = beanDefinitions;
this.singletons = singletons;
}
// 주어진 타입에 대한 후보 빈 이름들을 찾습니다
public Set<String> findCandidateNamesForType(Class<?> type) {
Set<String> names = new HashSet<>();
// 1) 이미 등록된 싱글턴에서 찾기
for (Map.Entry<String, Object> entry : singletons.entrySet()) {
if (type.isAssignableFrom(entry.getValue().getClass())) {
names.add(entry.getKey());
}
}
// 2) 아직 생성되지 않은 BeanDefinition에서 찾기
for (Map.Entry<String, BeanDefinition> entry : beanDefinitions.entrySet()) {
if (type.isAssignableFrom(entry.getValue().getType())) {
names.add(entry.getKey());
}
}
return names;
}
/**
* 후보 빈들 중에서 primary 빈을 선택
*
* @param requiredType 요청된 타입
* @param candidates 후보 빈 이름들
* @param primaryTypeToNameMap 타입별 primary 빈 매핑
* @return primary 빈 이름 (없으면 null)
*/
public String choosePrimary(Class<?> requiredType, Set<String> candidates, Map<Class<?>, String> primaryTypeToNameMap) {
// 1) BeanDefinition 중 primary=true인 빈 찾기
List<String> primaries = candidates.stream()
.filter(name -> {
BeanDefinition def = beanDefinitions.get(name);
return def != null && def.isPrimary();
})
.toList();
if (primaries.size() == 1) {
return primaries.get(0);
}
if (primaries.size() > 1) {
throw new RuntimeException("@Primary beans conflict for type " + requiredType.getName() + ": " + primaries);
}
// 2) primaryTypeToNameMap fallback
String mapped = primaryTypeToNameMap.get(requiredType);
if (mapped != null && candidates.contains(mapped)) {
return mapped;
}
return null;
}
/**
* 주어진 타입의 모든 빈 이름을 BeanDefinition에서 찾기
* (BeanGraph에서 사용)
*
* @param type 찾을 타입
* @return 빈 이름 집합
*/
public Set<String> getBeanNamesForType(Class<?> type) {
Set<String> names = new HashSet<>();
for (BeanDefinition beanDef : beanDefinitions.values()) {
if (type.isAssignableFrom(beanDef.getType())) {
names.add(beanDef.getName());
}
}
return names;
}
}