SpringMVCソースコード分析3:初期化要求を転送するのDispatcherServlet

我々は最初のサーブレットのプログラミング、学習のJava Webだけでなく、それほどではないフレームワークを学ぶとき。必要に応じて書き換えdoGetメソッド、doPostメソッドは、我々が定義されたJSPページにジャンプした場合我々は、単にのHttpServletを継承するために行うための簡単な関数をされて開発しました。サーブレットクラスは、web.xmlにサーブレットクラスを登録し終えた後。

また、無他。私たちは、あなたがブラウザ上で私たちの書かれたページの出力を見ることができ、Webサーバを起動し、ブラウザのアドレスを入力してください。より良い上記のこのプロセスを理解するには、3段階のサーブレットのライフサイクルについて学ぶ必要がある、いわゆる「初期化サービス-破壊します」。

あなたは十分、SpringMVCのデザインのアイデアを理解するより多くの知識は、私は思います。SpringMVCのコースは、複雑なフレームワークとみなすことができるが、同時にそれは、サーブレット、世界で最も簡単なルールに従っており、それは「INIT-サービス-破壊」です。私たちは、実際には、分析のinitのDispatcherServletクラス()メソッドをSpringMVCの初期化プロセスを分析する必要がある、のは、それがDispatcherServletのものを見るために、この単純なビュー、オープンソースコードを見てみましょう。

コンフィギュレーションの要素を読み出し

EclipseのIDEは、Ctrl + Tの表情でオープンソースのDispatcherServletクラス。

DispatcherServletのクラス初期エントリ方式のinit()はinit()メソッドのHttpServletクラスがそれ自身の初期化動作を実装をオーバーライドし、クラスのHttpServletクラスへの直接後継としてクラスHttpServletBean、HttpServletBean親クラスで定義されています。

@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, this.environment));
            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");
        }
    }

ここinitServletBean()メソッドは、クラスHttpServletBean無空に実装された方法であり、その目的はつまり、独自の初期化ロジックを実装して、サブクラスに委ねられ、私たちは多くの場合、そのテンプレートメソッドデザインパターンを言います。SpringMVCこのモードのこの鮮やかな使用に、init()メソッドは、サブクラスinitServletBeanでFrameworkServlet()メソッドがトリガさによって上書きTemplate Methodパターン、SpringMVC実際の初期化処理において、テンプレート法です。

init()メソッド、BeanWrapperを伴うcatchブロックコードパッケージ、PropertyValues、クラスのこれらの内部春ResourceEditor一番下で見てみてください。上記のコードの具体的な実装の詳細に入るためには、Springフレームワークのソースコードのかなり深い知識を持っている必要があります。私たちは、コードがこの試みに何をするかを分析するために、上記のコードや設計思想の影響から、シンプルに複雑避けるためにここにいる、catchブロック:

  • リソースファイルエディタに文字列を登録し、以下のサーブレットを作ります このように、所与のソースSpringMVC豆フレームプロファイル:状構成要素は、「クラスパス」として使用することができます。
  • このDispatcherServletの次のweb.xmlサーブレットで DispatcherServletを読み取るためのJavaBean方法(すなわち、セッタ法による)を使用して構成要素。

これらの2点が、私はこの点を説明するための例の下に渡したいです。

私は次のようにDispatcherServletの構成があるweb.xmlに登録しました:

<!-- springMVC配置开始 -->
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/spring-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- springMVC配置结束 -->

あなたが見ることができる、私は名前のcontextConfigLocationにサインアップ 要素、値「クラスパス:春/スプリングservlet.xml」は、これはまた、しばしば方法SpringMVCプロファイルパスを指定するために使用されます。フレーム要素を初期化するための設定を読み込むために、クラスパス内のリソースファイルに「クラスパス春/春-servlet.xml」この文字列を変換しますのこれらの上記のtry、catchブロックのコードラップ役割はにあります。設定ファイルバネ-servlet.xml、次の春に私のプロジェクトフォルダで。

別の効果は、その後、即ち上記継承階層のDispatcherServlet直接の親クラス、このsetContextConfigLocation()メソッドがFrameworkServletクラスで定義されているのDispatcherServlet setContextConfigLocationによって提供される()メソッド、contextConfigLocationの値を読み出すことである、と。

私たちは、あなたが以下のデバッグの結果を見ることができ、Webプロジェクトを開始し、ブレークポイントの上setContextConfigLocation()メソッドをマーク。

著者HttpServletBeanクラスは、有名な春のロッド・ジョンソンの父です。POJOプログラミング哲学のマスターとして、彼はこのクラスでHttpServletBeanを設計し、依存性注入を使用してのアイデアが完成します 素子構成をお読みください。彼は、HttpServletBeanこのクラスの目的はここにもある引き出さ読んサーブレットクラスへの「依存性注入のアプローチです 構成情報」が、ここでは、セッターインジェクションことは明らかです。

デザインのアイデアHttpServletBeanクラスを理解し、我々はまた、あなたがそれの恩恵を受けることができる方法を知っています。具体的には、私たちはこのメソッドのプロパティ、プロパティプラスセッターのクラス定義では、HttpServletBeanクラス(のDispatcherServlet好き)を継承、我々はできます 値のために定義された要素。クラスが初期化された後、値は内に注入され、我々は定型getInitParameter()の使用方法だけでなく、春のリソースエディタ機能を楽しむために自由を避け、直接それを使用することができ、あなたは、web.xmlことができ、 「クラスパス:」でリソースファイルは、直接クラスパスを指定します。

SpringMVC自体後宣言しcontextConfigLocation文字列パラメータを設定するために使用されるコンテキストの初期化を容易にするためには、それはリソース・タイプとして宣言され、同じことが成功して獲得することができるが、なお。読者がテストで自分の相続HttpServletBeanサーブレットクラスを記述し、それをデバッグするためのパラメータを設定することが奨励され、これは、プロセスの設定パラメータの理解を得るのを助けることができます。

コンテナのコンテキストを作成します。

言及した記事は、SpringMVC春コンテナは、Beanコンテナは、独自のコンテキストを有し、独自の構成要素を保持するために使用されます。SpringMVC初期化の過程において、重要なステップは、コンテナ・コンテキストを確立することである、とFrameworkServletクラスで行われ、このコンテキスト確立処理()メソッドは、上記initServletBean init()メソッドによってトリガされます。

@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");
        }
    }

initFrameworkServlet()メソッドは空無に実装される方法で、いくつかの定型コードを削除し、その後、このinitServletBean()メソッドは、非常に明確に何をされていません。

this.webApplicationContext = initWebApplicationContext();

これはWebApplicationContextは、プロセスのコンテキストから引き出さ確立するために使用されるSpringMVCクラスのシステムで設計された、このクラスのことを話すFrameworkServlet簡単なコードです。

initWebApplicationContext()メソッドは、パッケージ容器Springコンテキストを構築するプロセス全体、ロジック内以下:

  1. ContextLoaderListener取得とのServletContextのルートコンテキストによって初期化に登録され、rootContextと称される
  2. webApplicationContextが空でなかった場合、それはクラスはプログラムコンテキストを介して容器内にサーブレット(()内ServletContext.addServletサーブレット3.0以降)に登録されていることを示し、プログラミング式で渡されます。この文脈の中で渡されたが、その親コン​​テキストに、rootContextコンテキストを初期化されていない場合は、初期化、または直接使用します。
  3. WACは変数を参照しているかどうかがnullの場合、ステップ2が設定は式によってプログラムが登録されたサーブレットコンテナではないことを示す、コンテキスト(すなわち、プログラム方法の着信コンテキストかどうか)、確立された場合にWAC == NULLを終了したか否かを判定するインチ このとき、ContextAttributeでキー属性の値を与えることを見つけるために、のServletContextのコンテキストで見つけ、説明とコンテキストレジスタは直接そうでない場合、ContextAttributeで初期化されています。
  4. ヌルへのWAC変数の参照を確認し、WACは== nullがコンテキストの新しい親コンテキストを確立するために、createWebApplicationContext(rootContext)を呼び出し、成功せずに2つのステップ2と3のそのコンテキストの初期化戦略を示し、この時間は確立された場合rootContextコンテナ要素としてSpringMVCコンテキストを配置。我々はコンテキストを使用するほとんどの場合、それはこの新しい文脈です。
  5. これらの3つの初期コンテキストポリシーがonRefresh(ApplicationContextのコンテキスト)メソッドをコールバック(コールバックメソッドは、ポリシーに応じて異なっている)、この方法は、基準として上記で得られたコンテキストに、OnRefreshのDispatcherServletクラスは上書きされる、デフォルトの実装クラスSpringMVC終了します初期化。
  6. 最後に、これはのServletContextコンテキストで公開されます、つまり、コンテキストとのServletContextの属性として設定web.xmlの登録名に関連するキーの値を持つサーブレットクラス。あなたはのServletContextに公開すること、デフォルトはpublishContextの値を変更することにより、真であるかどうかを決定することができます。

上記トラッキング6:00 FrameworkServletクラスコードの比較処理コンテキストが明確に確立することができるコンテナ全体を理解し、FrameworkServletコンテキストSpringコンテナと関連するサーブレットを作成するために使用されるクラスを設計することを理解することができ、そしてServletContextへ登録します。オープンシステムを逃れるSpringMVC、我々はまた、FrameworkServletクラスを継承することができSpringコンテナの統合、FrameworkServletとHttpServletBeanの利益のために、それは独立して使用することができるクラスです。SpringMVC全体のデザイン、すべてが開閉の原則を反映して、1点も明らかにあります。

デフォルトの実装クラスの初期化SpringMVC

FrameworkServletクラス初期化処理フローにおいて、コンテキストが確立された後、コールバックonRefresh介して(ApplicationContextのコンテキスト)のDispatcherServletクラスに進みます。

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

DispatcherServletクラスは、スーパークラスFrameworkServlet onRefresh(ApplicationContextのコンテキスト)メソッドをオーバーライドSpringMVC様々なプログラミング要素の初期化を提供します。もちろん、これらのプログラム要素は、のような1つのBeanコンテナコンテキストが存在しています。initStrategiesにカプセル化された固有の初期化戦略、()メソッド。

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

initHandlerMappings(コンテキスト)メソッドは、例えば、これらの戦略SpringMVCプログラミング要素を初期分析どこに、他の方法は、初期化同様の戦略に基づいています。

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<HandlerMapping>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                OrderComparator.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.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }

インターフェースはHandlerMappingのデフォルト実装クラスを初期化されるときに、豆のすべてのタイプのコンテキストをHandlerMappingますtrueにdetectAllHandlerMappings変数のデフォルト値は、handlerMappingsリスト変数に登録されています。手動でfalseに設定した場合、それは豆がhandlerMappingという名前取得しようと、一つだけの要素を新しいリストを作成し、handlerMappingsに割り当てます。場合は、コンテキスト内で定義された豆の独自のHandlerMappingの種類を提供しないように、上記のプロセスの後、handlerMappings変数は、空のまま。この時点で、SpringMVCはhandlerMappingsを初期化するために、デフォルトの初期化戦略を使用します。

getDefaultStrategiesにポイントが見えます。

@SuppressWarnings("unchecked")
    protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
        String key = strategyInterface.getName();
        String value = defaultStrategies.getProperty(key);
        if (value != null) {
            String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
            List<T> strategies = new ArrayList<T>(classNames.length);
            for (String className : classNames) {
                try {
                    Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                    Object strategy = createDefaultStrategy(context, clazz);
                    strategies.add((T) strategy);
                }
                catch (ClassNotFoundException ex) {
                    throw new BeanInitializationException(
                            "Could not find DispatcherServlet's default strategy class [" + className +
                                    "] for interface [" + key + "]", ex);
                }
                catch (LinkageError err) {
                    throw new BeanInitializationException(
                            "Error loading DispatcherServlet's default strategy class [" + className +
                                    "] for interface [" + key + "]: problem with class file or dependent class", err);
                }
            }
            return strategies;
        }
        else {
            return new LinkedList<T>();
        }
    }

それは方法のパラダイムである、すべてのデフォルトの初期化戦略SpringMVCのプログラミング要素を前提としています。内容物を比較するための直接的な方法は、クラスの名前に伝達され、この変数実装クラスのプロパティdefaultStrategiesから取得した結合は、次に初期化を反映です。

defaultStrategies変数を初期化することで説明する必要があり、それがの静的初期化コードブロックのDispatcherServletにロードされます。

private static final Properties defaultStrategies;

    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());
        }
    }
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

キーと値のペアを経由して、この春-webmvc-3.1.3.RELEASE.jarジャーパッケージで、SpringMVCのデフォルトの実装クラスを記録し、このDispatcherServlet.properties、org.springframework.web.servlet内部のパッケージ。

# 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

これまでのところ、我々は、分析プロセスの実行initHandlerMappings(文脈)法、その他の初期化プロセスを完了したし、この方法は非常に似ています。すべての初期化メソッドの実装後、SpringMVC初期の正式な完成は、静かにWeb要求の到着を待っています。

概要

全体の初期化プロセスSpringMVCを確認し、我々はを通じて、参照HttpServletBean、FrameworkServlet、三つの異なるクラスレベル、SpringMVCの設計者は、3つの異なる機能は、テンプレートメソッドパターンを使用して抽象的なデザインは、3クラス階層内に固定されているのDispatcherServlet 。どのHttpServletBeanを完了しました 注射依存構成要素、FrameworkServletコンテキストの確立が完了した容器は、DispatcherServletの初期化戦略は、SpringMVC特定のプログラミング要素が達成されます。

画像のキャプション

おすすめ

転載: www.cnblogs.com/xll1025/p/11407916.html