spring boot は、tomcat、jetty、undertow など、現在主流のサーブレット コンテナをサポートしており、これらのサーブレット コンテナはプロジェクトに簡単に統合できるため、開発や運用保守の負担が軽減されます。従来のアプリケーション開発には複雑な手順が必要です: tomcat をインストール –> tomcat 構成を変更 –> war パッケージをデプロイ –> tomcat を開始 –> 運用とメンテナンス... この作業負荷は小さくありません (特にクラスターの展開と移行の場合)アプリケーション。 Spring Boot を採用すると、パッケージング - java -jar - 運用と保守まで、jar パッケージを自由にデプロイしてインストールするだけで済み、すべてが非常にシンプルになります。
ソースコードを分析する前に、まず 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
ファイルを読み込み、メソッドのパラメータで指定されたクラスを検索し、対応するインスタンス オブジェクトを作成して返します。さらに、並べ替えもサポートされており、次の方法で並べ替えることができます。
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;
EmbeddedServletContainer を使用して埋め込みサーブレット コンテナをカプセル化し、コンテナのライフ サイクルを制御するための
start、
stop およびその他のインターフェイスを提供します。クラス図に示されている 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 のクラス図を見てみましょう。
EmbeddedServletContainer## を作成するために使用されるファクトリ パターンです。 #、つまり、埋め込みサーブレット コンテナを作成するために使用されます。このインターフェイスには getEmbeddedServletContainer
メソッドが 1 つだけあります。
メソッド呼び出しスタックを見てください。 GenericWebApplicationContext#onRefresh()
メソッドが EmbeddedWebApplicationContext
に書き換えられ、getEmbeddedServletContainer
メソッドが呼び出されてサーブレット コンテナが作成されます。次に、この作成プロセスを分析します。 主要なコードは次のとおりです (例外処理は省略):
<div class="code" style="position:relative; padding:0px; margin:0px;"><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 && localServletContext == null) {
// 从容器中获取bean,如果使用tomcat则返回TomcatEmbeddedServletContainerFactory
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer());
}
else if (localServletContext != null) {
getSelfInitializer().onStartup(localServletContext);
}
initPropertySources();</pre><div class="contentsignin">ログイン後にコピー</div></div>
最初にメイン フローチャートを作成しましょう
由上图可知,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'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 サイトの他の関連記事を参照してください。