← 解説「Spring が決めていること、決めていないこと」に戻る
サンプルコードで身につける: Spring が決めていること、決めていないこと
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1同じ5クラスを6通りに置いた結果
同じ5のアプリを、の配置だけ変えて6通り作り、それぞれ起動して同じ URL を呼んだ結果です。の配下にある限り、フォルダの名前や分け方は応答に影響しませんでした。404 になったのは、起動クラスだけを隣のパッケージへ移した変種です。
変種 クラスの置き場所 GET /orders/1layered controller/ service/ repository/ domain/ (層別) 200feature 全部 order/ (機能別。Boot リファレンスの例の形) 200flat 全部ルートパッケージ com.example.shop に平置き 200weird banana/ x/y/z/ misc/stuff/ things/ 200component layered と同じ配置で @Service を @Component に替えた 200outside 起動クラスだけ com.example.shop.app へ (他は layered と同じ) 404
2リソースの既定の置き場所
が決めている2つ目です。 の下にファイルを置いて試すと、設定ファイルは直下と config/ のものが読まれ、settings/ のものは読まれませんでした。、、resources、resources のファイルは配信され、assets は 404 でした。フォルダ名は URL に現れません。
$ tree src(resources 以下を抜粋)└── resources├── META-INF│ └── resources│ └── d.txt├── application.properties├── assets│ └── e.txt├── config│ └── application.properties├── public│ └── b.txt├── resources│ └── c.txt├── settings│ └── application.properties└── static└── a.txt$ curl http://localhost:8080/propsshop.greeting = from application.properties at the classpath rootshop.extra = from config/application.propertiesshop.other = (not set)$ curl -i http://localhost:8080/a.txtHTTP/1.1 200Content-Type: text/plainserved from static/$ curl -i http://localhost:8080/b.txtHTTP/1.1 200Content-Type: text/plainserved from public/$ curl -i http://localhost:8080/c.txtHTTP/1.1 200Content-Type: text/plainserved from resources/$ curl -i http://localhost:8080/d.txtHTTP/1.1 200Content-Type: text/plainserved from META-INF/resources/$ curl -i http://localhost:8080/e.txtHTTP/1.1 404Content-Type: application/json{"timestamp":"2026-10-01T22:31:35.811Z","status":404,"error":"Not Found","path":"/e.txt"}$ curl -i http://localhost:8080/static/a.txtHTTP/1.1 404
3名前ではなくアノテーションで見分ける(模型)
クラスの名前や置き場所を見ずに、の有無だけで部品を選ぶ、という見分け方の模型です。 そのものではありませんが、考え方は同じです。Banana という名前でも印があれば登録され、OrderService という名前でも印が無ければ無視されます。
Java
4起動クラスを隣へ移すと、エラー無しで 404 になる
起動クラスだけを com.example.shop.app に移した変種です。controller や service は app の配下ではなく隣にあるので、走査の範囲から外れます。ログには Started と出て起動は成功しており、エラーも警告もありません。リクエストして初めて 404 で気づきます。
$ tree src (変種 outside)src└── main├── java│ └── com│ └── example│ └── shop│ ├── app│ │ └── ShopApplication.java│ ├── controller│ │ └── OrderController.java│ ├── domain│ │ └── Order.java│ ├── repository│ │ └── OrderRepository.java│ └── service│ └── OrderService.java└── resources└── application.properties--- application log(時刻を省き、桁揃えの空白を詰めた)... INFO 1 --- [shop] [main] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'... INFO 1 --- [shop] [main] com.example.shop.app.ShopApplication : Started ShopApplication in 0.655 seconds (process running for 0.885)$ curl -i http://localhost:8080/orders/1HTTP/1.1 404...{"timestamp":"2026-10-01T22:31:15.320Z","status":404,"error":"Not Found","path":"/orders/1"}
5深い構成は誰の設計か
前の回までに出てきた深いパスの各部分を、決めている主体ごとにまとめた表です。Spring / Spring Boot の行にあるのは、走査の起点との既定位置だけです。層の名前や、層別か機能別かはチームの慣習で、Spring の規則ではありません。
決めているもの 何を決めているか 例のパスでの該当部分Java 言語 + javac + JVM パッケージ名の . がディレクトリの / になる。 jp/co/example/shop/order/application/service/impl/public クラス名 = ファイル名 OrderServiceImpl.javaビルドツール ソース・リソース・テストの置き場所、出力先、 src/main/java/ (src/main/resources/、target/)(Maven / Gradle) モジュールの単位 order-service/ に pom.xml名前付けの慣習 逆ドメインで始める jp/co/example/Spring / Spring Boot スキャンの起点 (起動クラスのパッケージ配下) と、 shop/order/ に起動クラスを置けばその配下、リソースの既定位置だけ という関係のみチームの慣習 リポジトリ内の区分、モジュール分割、製品名・機能名、 repo/backend/order-service/、shop/order/、層の名前、層別か機能別か application/service/impl/