zenn.skin 무료버전 배포중!
자세히보기

Web/Spring

[Spring Web 6.1] DispatcherServlet 뜯어보기 - getter & setter

koosco! 2024. 10. 4. 23:18

getter

요소에 대한 getter

@Nullable
public final MultipartResolver getMultipartResolver() {
    return this.multipartResolver;
}

@Nullable
public final List<HandlerMapping> getHandlerMappings() {
    return this.handlerMappings != null ? Collections.unmodifiableList(this.handlerMappings) : null;
}

getter에서 mutlpartResolver, handlerMappings는 말그대로 dispatcherServlet이 갖는 속성값을 반환해준다.

크게 얘기할 부분이 없다.

 

request에 사용되는 getter

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        Iterator var2 = this.handlerMappings.iterator();

        while(var2.hasNext()) {
            HandlerMapping mapping = (HandlerMapping)var2.next();
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }

    return null;
}

@Nullable
protected String getDefaultViewName(HttpServletRequest request) throws Exception {
    return this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null;
}

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        Iterator var2 = this.handlerAdapters.iterator();

        while(var2.hasNext()) {
            HandlerAdapter adapter = (HandlerAdapter)var2.next();
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }

    throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

getHandler

getHandler는 요청을 매개변수로 받고 이에 해당하는 handler를 handlerMappings에서 찾아서 반환하는 역할을 한다.

후에 doDispatch 메서드를 보면 getHandler를 호출하고 null이면 noHandlerFound Exception을 던지는 것을 확인할 수 있다.

 

getDefaultViewName

말그대로 defaultViewName을 반환하는 역할을 한다. applyDefaultViewName 메서드에서 요청으로부터 viewName을 받아서 ModelAndView에 설정할 때 사용된다.

 

getHandlerAdapter

handler를 매개변수로 받고 이에 해당하는 adapter를 반환하게 된다. adapter는 controller를 호출하게 되는데 이 때, 요청에 해당하는 handler를 처리할 수 있는 adapter를 찾는 역할을 한다.

 

spring의 dispatcherServlet은 Strategy 패턴을 잘 활용한다. 이전 포스팅에서 봤던 init을 할 때 초기화된 요소들이 dispatcherServlet에서 사용되는 strategy의 인터페이스가 되고, 해당 인터페이스에 대한 여러 개의 strategy 구현체 코드를 만들 수 있다.

예를들어, HandlerMapping의 경우 RequestMappingHandlerMapping, SimpleUrlHandlerMapping, BeanNameHandlerMapping을 사용한다. HandlerAdapter의 경우에도 이와 비슷하게 인터페이스에 대한 다양한 구현체 Strategy를 사용한다.

 

protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
    List<T> strategies = this.getDefaultStrategies(context, strategyInterface);
    if (strategies.size() != 1) {
        throw new BeanInitializationException("DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
    } else {
        return strategies.get(0);
    }
}

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    if (defaultStrategies == null) {
        try {
            ClassPathResource resource = new ClassPathResource("DispatcherServlet.properties", DispatcherServlet.class);
            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
        } catch (IOException var15) {
            throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + var15.getMessage());
        }
    }

    String key = strategyInterface.getName();
    String value = defaultStrategies.getProperty(key);
    if (value == null) {
        return Collections.emptyList();
    } else {
        String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
        List<T> strategies = new ArrayList(classNames.length);
        String[] var7 = classNames;
        int var8 = classNames.length;

        for(int var9 = 0; var9 < var8; ++var9) {
            String className = var7[var9];

            try {
                Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                Object strategy = this.createDefaultStrategy(context, clazz);
                strategies.add(strategy);
            } catch (ClassNotFoundException var13) {
                throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var13);
            } catch (LinkageError var14) {
                throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var14);
            }
        }

        return strategies;
    }
}

getDefaultStrategy는 resolver, requestToViewNameTranslator, FlashMapManager를 초기화할 때 해당하는 전략을 가져오기 위해 사용된다.

getDefaultStrategies는 handlerMappings, handlerAdapters, ExceptionResolvers, ViewResolvers를 초기화할 때 1개 이상의 전략들을 가져오기 위해 사용된다.

각 요소마다 전략들을 갖기 때문에 이에 대해서는 각각의 코드를 뜯어보면서 살펴볼 예정이다.

 

setter

public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
    this.detectAllHandlerMappings = detectAllHandlerMappings;
}

public void setDetectAllHandlerAdapters(boolean detectAllHandlerAdapters) {
    this.detectAllHandlerAdapters = detectAllHandlerAdapters;
}

public void setDetectAllHandlerExceptionResolvers(boolean detectAllHandlerExceptionResolvers) {
    this.detectAllHandlerExceptionResolvers = detectAllHandlerExceptionResolvers;
}

public void setDetectAllViewResolvers(boolean detectAllViewResolvers) {
    this.detectAllViewResolvers = detectAllViewResolvers;
}

public void setCleanupAfterInclude(boolean cleanupAfterInclude) {
    this.cleanupAfterInclude = cleanupAfterInclude;
}

Spring의 요청 처리 흐름을 구성하는 다양한 전략 컴포넌트들을 초기화하거나 설정할 때 사용된다.

setter는 요청 처리 시 사용할 구성 요소들을 자동으로 검색할지 여부를 결정하거나, DispatcherServlet의 동작 방식을 조정하는 데 사용된다.

 

위 setter 값들은 아래와 같이 dispatcherServlet에 default 값이 설정되어 있는데 이 값들은 공통적으로 사용할 빈들을 검색할 범위를 나타낸다.

true인 경우 모든 빈들을 검색하여 사용할 빈을 결정하고, false로 설정된 경우 우선 순위가 가장 높은 하나의 빈만을 사용하게 된다.

private boolean detectAllHandlerMappings = true;
private boolean detectAllHandlerAdapters = true;
private boolean detectAllHandlerExceptionResolvers = true;
private boolean detectAllViewResolvers = true;
private boolean throwExceptionIfNoHandlerFound = true;
private boolean cleanupAfterInclude = true;

굳이 false로 설정할 일도 없을 것 같고, dispatcherServlet 설정값을 건드릴 일은 없으니 이후에 handlerMapping부분이나 adapter 부분을 정리하면서 다시 살펴보려 한다.

 

'Web/Spring'의 다른글

  • 현재글 [Spring Web 6.1] DispatcherServlet 뜯어보기 - getter & setter

관련글