ホームページ  >  記事  >  Java  >  SpringBoot が Tomcat を統合する方法は何ですか?

SpringBoot が Tomcat を統合する方法は何ですか?

王林
王林転載
2023-05-14 19:43:141081ブラウズ

spring boot は、tomcat、jetty、undertow など、現在主流のサーブレット コンテナをサポートしており、これらのサーブレット コンテナはプロジェクトに簡単に統合できるため、開発や運用保守の負担が軽減されます。従来のアプリケーション開発には複雑な手順が必要です: tomcat をインストール –> tomcat 構成を変更 –> war パッケージをデプロイ –> tomcat を開始 –> 運用とメンテナンス... この作業負荷は小さくありません (特にクラスターの展開と移行の場合)アプリケーション。 Spring Boot を採用すると、パッケージング - java -jar - 運用と保守まで、jar パッケージを自由にデプロイしてインストールするだけで済み、すべてが非常にシンプルになります。

SPI

ソースコードを分析する前に、まず Spring の SPI メカニズムを理解しましょう。 jdk はアプリケーションの拡張を容易にするためにデフォルトの SPI 実装 (ServiceLoader) を提供しており、dubbo にも独自の SPI があることがわかっています。同じことが Spring にも当てはまります。これにより、開発者は META-INF/spring.factories ファイルを通じて拡張できる SpringFactoriesLoader が提供されます。理解しやすいように例を示します

ApplicationContextInitializer を Spring コンテナーに追加して初期化作業を行う場合は、Spring が提供する SPI 関数を使用してこの要件を完了できます。

まず、プロジェクト内に META-INF/spring.factories ファイルを作成します。ファイルの内容は次のとおりです:

org.springframework.context。 ApplicationContextInitializer= \

別のテスト ケースを作成すると、SPI を通じて定義した ApplicationContextInitializer を取得できます。非常に単純な関数のように見えますが、Spring Boot はこの強力な拡張ポイントを使用して、一般的に使用されるオープンソース フレームワークを Spring フレームワークに基づいて統合します。

@Test
public void testSpringSpi() {
    List<ApplicationListener> listeners = SpringFactoriesLoader.loadFactories( ApplicationListener.class, 
            ClassUtils.getDefaultClassLoader() );
    System.out.println( listeners );

これを見てみましょう SpringFactoriesLoader のキーコードは次のとおりです。 META-INF/spring.factories ファイルを読み込み、メソッドのパラメータで指定されたクラスを検索し、対応するインスタンス オブジェクトを作成して返します。さらに、並べ替えもサポートされており、次の方法で並べ替えることができます。

  • ##org.springframework.core.Ordered: このインターフェイスを実装します。

  • org .springframework.core.annotation.Order: Annotation

  • javax.annotation.Priority: Annotation

  • public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
        List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
        List<T> result = new ArrayList<T>(factoryNames.size());
        for (String factoryName : factoryNames) {
            result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
        }
        AnnotationAwareOrderComparator.sort(result);
        return result;
次に、Spring How を分析しましょうboot は SPI メカニズムを使用して tomcat を統合します

Tomcat 用 SpringBoot

Tomcat 統合のソース コードを分析する前に、まず EmbeddedServletContainer

EmbeddedServletContainer:

Spring は

EmbeddedServletContainer を使用して埋め込みサーブレット コンテナをカプセル化し、コンテナのライフ サイクルを制御するための startstop およびその他のインターフェイスを提供します。クラス図に示されている tomcat 、jetty、undertow コンテナーの実装

スプリング ブートで最も一般的に使用される

SpringBootApplication アノテーションを見てみましょう。この EnableAutoConfiguration は自動構成のために Spring Boot によって使用されるアノテーションです。

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    // code......

spring-boot-autoconfigure で多数の SPI 構成を確認できます。モジュールの一部は次のとおりです

# Auto Configure

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\

オリジナルの

EnableAutoConfiguration アノテーションは EmbeddedServletContainerAutoConfiguration を導入しており、これは組み込みサーブレット コンテナの構成クラスです。Tomcat、jetty、および undertow はすべてこのクラスにあります、@ConditionalOnClassAnnotation を通じて、さまざまなサーブレット コンテナがロードされます。ただし、このクラスは TomcatEmbeddedServletContainerFactory を登録するだけであり、すべての混乱を解決するには十分ではありません。心配しないで、まず TomcatEmbeddedServletContainerFactory のクラス図を見てみましょう。

上記のクラス図からわかるように、次のインターフェイスを実装します。

  • EmbeddedServletContainerFactory:

    EmbeddedServletContainer## を作成するために使用されるファクトリ パターンです。 #、つまり、埋め込みサーブレット コンテナを作成するために使用されます。このインターフェイスには getEmbeddedServletContainer メソッドが 1 つだけあります。

    ConfigurableEmbeddedServletContainer:
  • の構成に使用されます。 EmbeddedServletContainer
  • (ポート、コンテキスト パスなどについての話)

    #上記 2 つのインターフェイスを分析した結果、サーブレット コンテナの作成作業は # によって完了したことがわかります。 ##EmbeddedServletContainerFactory
getEmbeddedServletContainer

メソッド呼び出しスタックを見てください。 GenericWebApplicationContext#onRefresh() メソッドが EmbeddedWebApplicationContext に書き換えられ、getEmbeddedServletContainer メソッドが呼び出されてサーブレット コンテナが作成されます。次に、この作成プロセスを分析します。 主要なコードは次のとおりです (例外処理は省略): <pre class="brush:java;">EmbeddedWebApplicationContext.java @Override protected void onRefresh() { super.onRefresh(); createEmbeddedServletContainer(); } private void createEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer; ServletContext localServletContext = getServletContext(); if (localContainer == null &amp;&amp; localServletContext == null) { // 从容器中获取bean,如果使用tomcat则返回TomcatEmbeddedServletContainerFactory EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory(); this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) { getSelfInitializer().onStartup(localServletContext); } initPropertySources();</pre>最初にメイン フローチャートを作成しましょう

SpringBoot が Tomcat を統合する方法は何ですか?

由上图可知,EmbeddedWebApplicationContext在执行onRefresh方法的时候,首先调用父类的onRefresh,然后从容器中获取EmbeddedServletContainerFactory的实现类。由于我们在 classpath 下面可以获取 tomcat 的 jar 包,因此EmbeddedServletContainerAutoConfiguration会在 spring 容器中注册TomcatEmbeddedServletContainerFactory这个 bean。然后,由它创建TomcatEmbeddedServletContainer,我们来看看具体的创建过程,代码如下所示:

TomcatEmbeddedServletContainerFactory.java
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
        ServletContextInitializer... initializers) {
    Tomcat tomcat = new Tomcat();   // 实例化 apache Tomcat 
    File baseDir = (this.baseDirectory != null ? this.baseDirectory
            : createTempDir("tomcat"));
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    // 创建 Connector 组件,默认使用org.apache.coyote.http11.Http11NioProtocol
    Connector connector = new Connector(this.protocol); 
    tomcat.getService().addConnector(connector);
    // 支持对 Connector 进行自定义设置,比如设置线程池、最大连接数等
    customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    configureEngine(tomcat.getEngine());
    for (Connector additionalConnector : this.additionalTomcatConnectors) {
        tomcat.getService().addConnector(additionalConnector);
    }
    prepareContext(tomcat.getHost(), initializers);
    return getTomcatEmbeddedServletContainer(tomcat);

首先是实例化Tomcat对象,然后创建Connector组件,并且对Connector进行相关的参数设置,同时也允许我们通过TomcatConnectorCustomizer接口进行自定义的设置。OK,创建了Tomcat实例之后,需要创建TomcatEmbeddedServletContainer,它依赖Tomcat对象,在构造方法中便会启动 Tomcat 容器,从而完成各个组件的启动流程

public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) {
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    this.autoStart = autoStart;
    initialize();
}
private void initialize() throws EmbeddedServletContainerException {
    synchronized (this.monitor) {
        addInstanceIdToEngineName();
        // Remove service connectors to that protocol binding doesn&#39;t happen yet
        removeServiceConnectors();
        // Start the server to trigger initialization listeners
        this.tomcat.start();
        // We can re-throw failure exception directly in the main thread
        rethrowDeferredStartupExceptions();
        Context context = findContext();
        ContextBindings.bindClassLoader(context, getNamingToken(context),
                    getClass().getClassLoader());
        // Unlike Jetty, all Tomcat threads are daemon threads. We create a
        // blocking non-daemon to stop immediate shutdown
        startDaemonAwaitThread();
    }

以上がSpringBoot が Tomcat を統合する方法は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。