springMVC(2)のDispatcherServletの初期化

DispatcherServletの理解

Webプロジェクトでは、のContextLoaderListener役割は、Beanオブジェクトと、より最近の前面の一部を管理するための親コンテナ、ビジネス関連のロジックを持つBeanオブジェクトの管理、子コンテナのディスパッチャインスタンスの一例です。ハンドルターゲットハンドラに対応する配信ルールに従って要求ダウン傍受。

DispatcherServletの継承

public class DispatcherServlet extends FrameworkServlet
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware

DispatcherServletのは、このような継承の数があります見ることができます。

HttpServletのクラス初心者ウェブは、一般的にプロジェクトは、その役割は(のような:getメソッド、ポスト方法、など)異なる要求メソッドを処理するためにあるときに使用され、あなたが最初の情報は、ServletContextオブジェクトを(initParamこのServletのために設定可能なされ得ることができます)。特に重要なのは、各サーブレットは、すべてのinit、サービスであることを、ライフサイクルの方法論は別のサーブレットのライフサイクルを表し破壊です。

HttpServletのクラスhttpServletBean抽象クラスを継承することに加えてEnvironmentCapable、EnvironmentAwareインタフェースを達成しました。これら二つのインターフェースの役割は、オブジェクトと設定環境オブジェクト環境の戻り型環境は、特に二つのインターフェースを提供GET / SETのタイプと同等です。主な役割はhttpServletBeanに後で使用するために対応する専用の変数を割り当てるように構成された抽象クラス情報(INIT-PARAM)でのweb.xmlのDispatcherServletです。

HttpServletBeanクラスFrameworkServlet ApplicationContextAware抽象クラスもインターフェイスを実装を達成することに加えて、インターフェースの役割は、ApplicationContextの方法を設定することです。その濃厚initServletBean抽象クラスメソッド、webApplicationContextのインスタンスに大きな役割をFrameworkServletと初期化を完了。

DispatcherServletのFrameworkServlet抽象クラスは、彼の主な機能は、残りのFrameworkServletの初期化と要求の処理を完了することで継承されます。

DispacherServlet初期化プロセス

DispacherServletものTomcatでサーブレットを使用して、サーブレットを継承見ることができる以上のことから、彼の標準的なライフサイクルに合わせて仕事を行うためにステップバイステップで完了する必要があります。
まず、initはまず、初期化され、一度だけ初期化され、あなたがあなたのリクエストを処理するために複数のサービスメソッドを使用することができた後、最終的に容器が破壊メソッドを使用します場合に閉とされるサーブレットにこのサーブレットを実行します。またDispacherServletサーブレットので(継承のHttpServletクラスは、時間のweb.xml構成も設定され、サーブレットと考える時)、その後も使用することができ、このようなステップを経る必要があるのDispatcherServlet。

init()メソッドではまず見て

public final void init() throws ServletException {
		//   将web.xml  中 dispatcherServlet的配置信息以key-value形式包装到PropertyValue中
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				initBeanWrapper(bw);
                                //将为dispatchServlet配置的initParam赋值给相关变量
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				throw ex;
			}
		}
		initServletBean();
	}

上記機能情報(INIT-paramが)のweb.xml dispatchServlet PropertyValueを、次いでPropertyValuesに配置されたパッケージ内に配置されています。
このクラスのクラスのインスタンスにパッケージdispatchServlet BeanWrapper操作SPINGのJavaBeanプロパティによって提供されるツールであり、オブジェクトのプロパティを変更するために直接使用することができます。パラメータbw.setPropertyValues(PVS、真)このメソッドは、プロパティに対応する設定を構成することです。
initServletBeanは()FrameworkServletで具現テンプレート法、です。

それは、この機能を実現することがいかにについては、探求を行っていません。デバッグ情報を通じて、あなたは確かに、オブジェクトのプロパティに、当社の構成設定を確認することができます。
HR-W10

INITの実装の非存在下で()メソッドはCONTEXTID、contextConfigLocation値がnullで見ることができます

新しいServletConfigPropertyValues後に行わPropertyValuesのPVSは=(のgetServletConfig()、this.requiredProperties)文はContextConfigLocation構成情報PropertyValueをパッケージ化し、リストPropertyValuesに置かれます。

bw.setPropertyValues実行した後(PVSを、真)の文を見ることができるContextConfigLocationプロパティが値に設定されている(のみ設定ContextConfigLocationパラメータので、CONTEXTIDまたはヌルそう)。

そして、何かをするinitServletBeanを見て()メソッドを取ります

protected final void initServletBean() throws ServletException {
		....
		try {
			this.webApplicationContext = initWebApplicationContext();
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}
	}

私たちは、この関数はinitFrameworkServlet()メソッドはテンプレートが、サブクラスのDispatcherServletと具体的な実現である他の二つの機能を、と呼ばれていることがわかります。

そのため、メイン表情initWebApplicationContext()メソッドはありません。

	protected WebApplicationContext initWebApplicationContext() {
		//从servletContext中查找是否设置了rootContext,也就是ContextLoaderListener实例化的webApplicationContext
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			//如果在构建时注入了一个webApplicationContext->使用它
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                                //在当前容器不是活动状态时
				if (!cwac.isActive()) {
                                        //设置父容器
					if (cwac.getParent() == null) {
						cwac.setParent(rootContext);
					}
                                        //进行相关配置并实例化单例bean
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
                //如果没有通过构造方法注入,就查看servletContext中是否有DispacherServlet实例化的WebApplicationContext(通过查找Atrribute的方式)
		if (wac == null) {
			wac = findWebApplicationContext();
		}
                //如果之前没有实例化过,那就实例化一个
		if (wac == null) {
			wac = createWebApplicationContext(rootContext);
		}
                //初始化一些处理请求的工具
		if (!this.refreshEventReceived) {
			synchronized (this.onRefreshMonitor) {
				onRefresh(wac);
			}
		}
                //将WebApplicationContext放入servletContext中
		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			
		}

		return wac;
	}

私はおそらく見るので、いくつかのことを行うことができます。

ステップは、親コンテナ(rootContext)検索1.
ステップはWebApplicationContext入手2.
:(handlerMapping、handlerAdapter等など)ツールを使用する要求を処理初期3.onrefresh方法ステップを
ステップ4 webApplicationContextのServletContextはに提供
ステップ1とステップ図4は、理解しやすいシンプルです。主な洞察は、2と3を繰り返します。

ステップ2 --- 3つのステップを得るWebApplicationContext:

コンストラクタを注入することにより、1
入手2.のServletContextで(atrributeルックアップ属性は、属性名をするServletContextと異なる親コンテナを見つける。)
3.独自のインスタンス(プライマリ手段)

webApplicationContextをインスタンス化する方法を参照してください。

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		//获得要实例化的webApplicationContext的class对象,这里获得的是XmlWebApplicationContext   class对象
		Class<?> contextClass = getContextClass();
                //判断class对象是否是ConfigurableWebApplicationContext的子类
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
                //实例化一个
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
                //设置相关属性
		wac.setEnvironment(getEnvironment());
		wac.setParent(parent);
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			wac.setConfigLocation(configLocation);
		}
                //设置相关属性并实例化单例bean主要是(refresh方法)
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}

なぜ外観はxmlWebApplicationContextクラスオブジェクトで取得します。

	public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
        private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;

        public void setContextClass(Class<?> contextClass) {
		this.contextClass = contextClass;
	}

	public Class<?> getContextClass() {
		return this.contextClass;
	}

FrameworkServletは、デフォルト値を直接指定するには、もちろん、あなたもオブジェクト構成がConfigurableWebApplicationContextのサブクラスでなければならないことを提供すると、init-PARAMによりクラスオブジェクトの独自のwebApplicationContextを設定することができます。これは、コンフィギュレーション後contextConfigLocation contextClassオブジェクトと同じプロパティに注入されます。

configureAndRefreshWebApplicationContext(WAC)メソッドを見て、具体的に何をしますか。

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
                //设置Contextid(这个属性可以自己配置)
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
			}
		}
                
                //设置ServletContext属性
		wac.setServletContext(getServletContext());
                //设置servletConfig属性
		wac.setServletConfig(getServletConfig());
                //设置namespace属性(可以自己配置)
		wac.setNamespace(getNamespace());
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
		ConfigurableEnvironment env = wac.getEnvironment();
                //将servletContext,servletConfig作为属性保存在environment中
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}
                //在刷新给定的WebApplicationContext之前对其进行后处理(后处理相信了解springFramework的一定知道)
                // 这是个空方法
		postProcessWebApplicationContext(wac);
                //执行配置的实现了  ApplicationContextInitializer接口的类的initialize(C applicationContext)方法
		applyInitializers(wac);
                //ioc容器启动方法,会设置一些属性然后实例化没有设置懒加载的单例的bean
		wac.refresh();
	}

ルックapplyInitializers(WAC)メソッド

	protected void applyInitializers(ConfigurableApplicationContext wac) {
                //从servletContext中设置init-param中获得配置属性名为globalInitializerClasses的属性值
		String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);
		if (globalClassNames != null) {
			for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
                                //分解globalInitializerClasses属性值(可能一次配了多个,用,隔开的)
                                //然后loadInitializer方法实例化并放入contextInitializers中
				this.contextInitializers.add(loadInitializer(className, wac));
			}
		}
                // contextInitializerClass  配置在servlet的init-param属性中,然后通过跟ContextConfigLocation同样的方法注入
		if (this.contextInitializerClasses != null) {
			for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) {
				this.contextInitializers.add(loadInitializer(className, wac));
			}
		}
                // 进行排序
		AnnotationAwareOrderComparator.sort(this.contextInitializers);
                //一个一个的执行其initialize方法
		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
			initializer.initialize(wac);
		}
	}

ステップ3 ----見た目onRefresh方法は、これは中のDispatcherServletに実装されたテンプレート方法、です。

	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

initStrategies(コンテキスト)メソッドを見て

	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

要求の多様を扱うときに初期化ツールを使用していることがわかります。MultipartResolver、LocaleResolver、ThemeResolver、HandlerMapping、HandlerAdapter、HandlerExceptionResolver、RequestToViewNameTranslator、ViewResolvers、FlashMapManager含みます。

HandlerMapping:検索と応答要求に基づいてIntercepterハンドラプロセッサ。
HandlerAdapterは:プロセッサの使用として理解することができます。
HandlerExceptionResolver:例外を扱います。
ViewResolver: String型の名前、ウサギやビューの表示ロケールの種類に解決です。
RequestToViewNameTranslator: ViewResolverはビューを探すがVIEWNAMEに基づいていますが、いくつかの処理されたハンドラが設定ビューがたviewNameを設定されていないいない、あなたが必要とするからされ
たviewName要求を取得し、RequestToViewNameTranslatorはそれを行うことです。
LocaleResolver:分析ビューには、2つのパラメータが必要です:1がビュー名で、他のロケールです。ビュー名は、プロセッサによって返されるかRequestToViewNameTranslatorビューポートのデフォルトを使用して解決される
ロケールLocaleResolverによって解析され、図名。
ThemeResolver:パーステーマ。
MultipartResolverは:アップロード要求を処理するために、一般的なアプローチは、直接はgetFileファイルを得る彼らの方法を動員し、パッケージ化MltipartHttpServletRequestを要求することです。
FlashMapManager:FlashMapを管理するために、FlashMapリダイレクト主に送信パラメータに使用されます。

文の中で、これらのツールでのDispatcherServletの外観

	@Nullable
	private MultipartResolver multipartResolver;

	/** LocaleResolver used by this servlet */
	@Nullable
	private LocaleResolver localeResolver;

	/** ThemeResolver used by this servlet */
	@Nullable
	private ThemeResolver themeResolver;

	/** List of HandlerMappings used by this servlet */
	@Nullable
	private List<HandlerMapping> handlerMappings;

	/** List of HandlerAdapters used by this servlet */
	@Nullable
	private List<HandlerAdapter> handlerAdapters;

	/** List of HandlerExceptionResolvers used by this servlet */
	@Nullable
	private List<HandlerExceptionResolver> handlerExceptionResolvers;

	/** RequestToViewNameTranslator used by this servlet */
	@Nullable
	private RequestToViewNameTranslator viewNameTranslator;

	/** FlashMapManager used by this servlet */
	@Nullable
	private FlashMapManager flashMapManager;

	/** List of ViewResolvers used by this servlet */
	@Nullable
	private List<ViewResolver> viewResolvers;

あなたが見ることができるので、他の人が複数のツールを持つことができますが、一つだけのツールが存在することができます。

これらのツールを初期化する方法を参照してください。

private void initMultipartResolver(ApplicationContext context) {
		try {
			this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Default is no multipart resolver.
			this.multipartResolver = null;
		}
	}

MultipartResolverツールの初期化プロセスである:IOCがキャッチヌルへの割り当ての例外が表示されない場合は、最初のオブジェクト名IOCコンテナから=豆multipartResolver、コンテナを見つけます。

private void initLocaleResolver(ApplicationContext context) {
		try {
			this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
		}
	}

LocaleResolverツールの初期化プロセスは、次のとおりです。名前= Beanコンテナは、IOCからlocaleResolver、IOCコンテナ例外がスローされない場合、キャッチはこの声明の中で見ることができthis.localeResolver = getDefaultStrategy(コンテキスト、LocaleResolver.class)のオブジェクトを取得し、ウォンデフォルトのlocaleResolverはthis.localeResolverを与えました。

デフォルトLocaleResolverから来ますか?

static {
		try {
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
		}
	}

これは、静的なコードセグメントのDispatcherServletに言っている、ファイルがロードされたDispatchServlet.propertiesをされ
たファイルは、組織/ springframework /ウェブ/サーブレット/配置されて DispatcherServlet.propertiesの
ファイルの内容を:
org.springframework.web.servlet.LocaleResolver = org.springframework.web.servlet。 i18n.AcceptHeaderLocaleResolver
....

(彼は設定できませんでしたとき)、デフォルトのファイルクラス(文字列型)を設定するために必要なツールのいくつかは、反射法によるgetDefaultStrategyは、これらのデフォルトのツールをインスタンス化します

private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			// 找出 所有的handlerMappings  包括父Context中的
			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);
		}
	}

HandlerMappingはまた、HandlerMapping親クラスを見つけることが必要であるかどうかをdetectAllHandlerMappingsを設定することができます。

おすすめ

転載: www.cnblogs.com/zhangchenwei/p/12555126.html