spring mvcソース(一)ウェブコンテナの作成
もっと読む
spring mvcはmvcのオープンソースフレームです.springとは親子関係ですので、シームレスに対応しています.
spring mvc入口:
Displatch Servletソースは:
一つのservletの初期化はinit()の方法で行われます.まず一番上のクラスHttpServletBenから見て、次はHttpServletBenのinit()の方法の実現です.
Fraamew orkServlet類におけるonRefresh()方法は、具体的には実現されていないが、布団類は書き換えられており、サブタイプのDisplatch ServletでonRefresh()方法は以下のように実現される.
初期化Resolaver:
上のコンポーネント初期化は基本的に一つの主要なロジックに従っています.まず容器や資源から探して、見つけられないなら、配置ファイルの中でデフォルトの設定を使用します.
上のコードでspring mvcの初期化が完了しました.
spring mvcはmvcのオープンソースフレームです.springとは親子関係ですので、シームレスに対応しています.
spring mvc入口:
spring-mvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath*:/spring-mvc-servlet.xml
1
spring mvcのweb.xmlでの構成は上述の通りであり、これは標準的なservletの構成であり、入口はDisplatch Servletである.Displatch Servletソースは:
public class DispatcherServlet extends FrameworkServlet {
// ...
}
public abstract class FrameworkServlet extends HttpServletBean {
// ...s
}
public abstract class HttpServletBean extends HttpServlet
implements EnvironmentCapable, EnvironmentAware {
//
}
Disppatch Servletは上から分かります.HttpServletインターフェースを実現しましたので、設定もservletで構成します.一つのservletの初期化はinit()の方法で行われます.まず一番上のクラスHttpServletBenから見て、次はHttpServletBenのinit()の方法の実現です.
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
// Let subclasses do whatever initialization they like.
//
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
上記のコードから分かるように、方法の前半はいくつかの初期化構成をしています.initServletBenはFramw orkServletによって書き換えられています.次はFrame ebork ServletのinitServBen()の実現です. @Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
// ,
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
// , spring mvc
protected WebApplicationContext initWebApplicationContext() {
// , spring
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
// , spring
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
上のコードから分かります.spring mvc文脈とspring文脈の関係、spring mvc容器はサブ容器、springの容器は親容器です.だからspring mvcにcontrolerを配置する時、springに配置されたservice類を直接参照できます.したがって、web.xmlの構成では、先にspringの配置を配置してから、spring mvcの配置を配置してください.そうでないと、spring mvcのサブコンテナは親の容器のリソースを使用できません.Fraamew orkServlet類におけるonRefresh()方法は、具体的には実現されていないが、布団類は書き換えられており、サブタイプのDisplatch ServletでonRefresh()方法は以下のように実現される.
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
上のコードからDisplatch Servletで容器を更新する時、大量の初期化作業をしました.Resolaver,HandlerMapping,Adapterを初期化しました.初期化Resolaver:
private void initLocaleResolver(ApplicationContext context) {
try {
//
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
//
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver + "]");
}
}
}
デフォルトのrescorverについて:DisplatServletで最初に静的初期化のコードがあります. static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
デフォルトで設定ファイルを読み込みます.Dispactch Servletと同じパスでDEFAULT_.STRATEGIES_PATH;Displatch Servlet.propertiesです.# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
設定ファイルにはデフォルトのResolaver,HandlerMapping,Handler Adapterが配置されています. Orefsh()メソッドで初期化するコンポーネントにはデフォルトの設定があります.上のコンポーネント初期化は基本的に一つの主要なロジックに従っています.まず容器や資源から探して、見つけられないなら、配置ファイルの中でデフォルトの設定を使用します.
上のコードでspring mvcの初期化が完了しました.