Project Winter
Controller 기능 개발
서버 기능을 구현 후 예정대로 Controller
기능 개발을 하던 중 문제를 만났다.
Controller
interface Controller {
public Object handle(HttpServletRequest req, HttpServletResponse res);
}
이렇게 컨트롤러 인터페이스를 만들고 이를 구현한 컨트롤러 클래스들을 실제 핸들러로 사용하고자 했다.
HandlerMapping
public interface HandlerMapping {
void init();
Object findHandler(HttpServletRequest req);
}
HandlerMapping
을 구현한 클래스로 http method, uri 를 Controller
클래스를 매핑해주고, 요청이 들어오면 해당 http method 와 uri 를 통해 Controller
를 반환해주는 역할을 하는것으로 설계했다.
하지만 여기서 문제가 생겼다.
HandlerMapping 에서의 문제
HandlerMapping
의 init()
함수에서 http method, uri 와 Controller
클래스를 매핑해주려 했다. 하지만 어디에서도 Controller
의 http method, uri 를 받아올 수 없어서 매핑을 해주는 방법에 대해 엄청 고민했다. 일단 SpringFramework
에서 어떤 흐름인지 찾아봤다.
DispatchServlet - initHandlerMappings()
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
for (HandlerMapping mapping : this.handlerMappings) {
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}
DispatchServlet
에서 HandlerMapping
들을 초기화 해주는 함수이다.BeanFactoryUtils.beansOfTypeIncludingAncestors
를 통해 HandlerMapping
들을 받아오는거로 보이는데 구현 코드를 찾아가지 못했다..
추상화가 잘돼있고 호출되는 부분부터 역순으로 찾아가다 보니 구현 클래스를 찾아가기 어려운 부분이 있었다.
일단은 내 방식대로 구현을 해보기로 했다.
새로운 설계
내가 생각한 매핑 방법은 이용자가 설정 클래스를 구현하고, 해당 클래스에서 Controller
인터페이스를 구현한 클래스들을 등록해주고, 추가적으로 uri 와 http method 를 직접 매핑해주는 방법을 생각했다.
이런 방법을 구현하려면 애플리케이션 실행 시점에 설정 클래스를 로드 해야하고 생각한 방법은 xml 을 이용한 설정 방법, 그리고 @Configuration
애노테이션을 이용한 설정 방법을 생각했다.
그중 애노테이션 방법을 구현하기로 했고, 이걸 구현하기 위해 리플렉션을 먼저 구현하기로 했다.