Dev Study
← 解説「SpringApplication.run がやること」に戻る

サンプルコードで身につける: SpringApplication.run がやること

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1start.spring.io が生成する main クラス

で作ったプロジェクトに最初から入っているの全文です。自分のコードと呼べるのは run の1行だけで、ポート番号もサーバの種類もここには出てきません。それでもこのクラスを起動すると が 8080 番で待ち受けます。

package com.example.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebApplication {

	public static void main(String[] args) {
		SpringApplication.run(WebApplication.class, args);
	}

}

2起動ログを上から読む

上の クラスを起動したときのログ全文です( 4.1.1 / 25)。Tomcat initialized の行でポートが決まり、Started の行で run の主な仕事が終わっています。起動中の行は欄がどれも main で、起動の処理が の上で進んでいることが読めます。最後の2行は実験でを止めたときの終了処理です。

java -cp target/classes:(39 個の JAR) com.example.web.WebApplicationコマンド出力
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
 
:: Spring Boot :: (v4.1.1)
 
2026-10-01T13:18:59.532Z INFO 1 --- [web] [ main] com.example.web.WebApplication : Starting WebApplication using Java 25.0.4.1 with PID 1 (/work/web/target/classes started by root in /work/web)
2026-10-01T13:18:59.534Z INFO 1 --- [web] [ main] com.example.web.WebApplication : No active profile set, falling back to 1 default profile: "default"
2026-10-01T13:19:00.008Z INFO 1 --- [web] [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2026-10-01T13:19:00.017Z INFO 1 --- [web] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2026-10-01T13:19:00.017Z INFO 1 --- [web] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/11.0.24]
2026-10-01T13:19:00.035Z INFO 1 --- [web] [ main] b.w.c.s.WebApplicationContextInitializer : Root WebApplicationContext: initialization completed in 452 ms
2026-10-01T13:19:00.244Z INFO 1 --- [web] [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2026-10-01T13:19:00.247Z INFO 1 --- [web] [ main] com.example.web.WebApplication : Started WebApplication in 0.947 seconds (process running for 1.105)
2026-10-01T13:19:00.379Z INFO 1 --- [web] [ionShutdownHook] o.s.boot.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
2026-10-01T13:19:00.381Z INFO 1 --- [web] [tomcat-shutdown] o.s.boot.tomcat.GracefulShutdown : Graceful shutdown complete

3起動秒数を5回測る

同じ main クラスを、毎回新しいコンテナで5回起動した値です。条件は、依存が だけ・自作の なし・展開済みのクラスと 群から起動・ オプションなし・ファイルがキャッシュに載った状態・コンテナから見える CPU は 10 個です。左の列と右の列は別の数で、右は JVM の起動からの経過です。この条件での範囲であり、Spring Boot 一般の起動時間ではありません。

Started WebApplication in N seconds (process running for M) の N と M表
回 | Started ... in(秒) | process running for
---+----------------------+--------------------
1 | 0.947 | 1.105
2 | 0.865 | 1.073
3 | 0.734 | 0.9
4 | 0.732 | 0.896
5 | 0.718 | 0.871

4JAR を外すと Web アプリでなくなる

イベントを印字する同じクラスを、から Tomcat と まわりの JAR を外して起動した出力です。コードは変えていないのに種別は NONE になり、Tomcat の行が消え、のクラスも別のものになりました。下のコードは種別を決めている Spring Boot 4.1.1 の WebApplicationType の抜粋で、クラスがあるかどうかを調べています。4.1.1 では spring-boot-webmvc の JAR も判定役(Deducer)を登録しています。

Web 関連の JAR を外して EventsApp を起動([log] は起動ログ。時刻などは省略)コマンド出力
>> webApplicationType = NONE
>> event: ApplicationStartingEvent
>> event: ApplicationEnvironmentPreparedEvent
>> event: ApplicationContextInitializedEvent
[log] Starting EventsApp using Java 25.0.4.1 with PID 8 (/work/web/target/classes started by root in /work/web)
[log] No active profile set, falling back to 1 default profile: "default"
>> event: ApplicationPreparedEvent
>> event: ContextRefreshedEvent
[log] Started EventsApp in 0.474 seconds (process running for 0.608)
>> event: ApplicationStartedEvent
>> event: AvailabilityChangeEvent
>> CommandLineRunner.run args=[]
>> ApplicationRunner.run nonOptionArgs=[]
>> event: ApplicationReadyEvent
>> event: AvailabilityChangeEvent
>> run() returned: AnnotationConfigApplicationContext
>> event: ContextClosedEvent
// 出所: spring-boot 4.1.1 / org.springframework.boot.WebApplicationType(抜粋)
    private static final String[] SERVLET_INDICATOR_CLASSES = { "jakarta.servlet.Servlet",
            "org.springframework.web.context.ConfigurableWebApplicationContext" };

    /**
     * Deduce the {@link WebApplicationType} from the current classpath.
     * @return the deduced web application
     * @since 4.0.1
     */
    public static WebApplicationType deduce() {
        for (Deducer deducer : SpringFactoriesLoader.forDefaultResourceLocation().load(Deducer.class)) {
            WebApplicationType deduced = deducer.deduceWebApplicationType();
            if (deduced != null) {
                return deduced;
            }
        }
        return isServletApplication() ? WebApplicationType.SERVLET : WebApplicationType.NONE;
    }

    private static boolean isServletApplication() {
        for (String servletIndicatorClass : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(servletIndicatorClass, null)) {
                return false;
            }
        }
        return true;
    }

5NestJS の main.ts と並べる

NestJS では、コンテナを組み立てる create と、ポートを開く listen を自分で別々に呼びます。listen を書かなければサーバは立ちません。Spring Boot では run の1行で、クラスパスから Web アプリかどうかが決まり、必要なら Tomcat の起動まで進みます。書く量の差ではなく、ポートを開く判断をどこに置いたかの違いです。

// NestJS: main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule); // コンテナを組み立てる
  await app.listen(3000);                          // ポートを開くのは自分で呼ぶ
}
bootstrap();

// Spring Boot: 対応する部分は1行
//   SpringApplication.run(WebApplication.class, args);
// ポート番号は設定値(既定は 8080)、サーバを起動するかどうかはクラスパスで決まる

図やコードに出てくる用語(タップで説明)