Dev Study
← 解説「Spring が決めていること、決めていないこと」に戻る

サンプルコードで身につける: Spring が決めていること、決めていないこと

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

1同じ5クラスを6通りに置いた結果

同じ5のアプリを、の配置だけ変えて6通り作り、それぞれ起動して同じ URL を呼んだ結果です。の配下にある限り、フォルダの名前や分け方は応答に影響しませんでした。404 になったのは、起動クラスだけを隣のパッケージへ移した変種です。

配置の変種と GET /orders/1 の結果(Boot 4.1.1 / JDK 25。各1回)表
変種 クラスの置き場所 GET /orders/1
layered controller/ service/ repository/ domain/ (層別) 200
feature 全部 order/ (機能別。Boot リファレンスの例の形) 200
flat 全部ルートパッケージ com.example.shop に平置き 200
weird banana/ x/y/z/ misc/stuff/ things/ 200
component layered と同じ配置で @Service を @Component に替えた 200
outside 起動クラスだけ com.example.shop.app へ (他は layered と同じ) 404

2リソースの既定の置き場所

が決めている2つ目です。 の下にファイルを置いて試すと、設定ファイルは直下と config/ のものが読まれ、settings/ のものは読まれませんでした。、、resources、resources のファイルは配信され、assets は 404 でした。フォルダ名は URL に現れません。

src/main/resources 以下に置いたものと、起動後の応答(Boot 4.1.1。応答ヘッダは抜粋)コマンド出力
$ 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/props
shop.greeting = from application.properties at the classpath root
shop.extra = from config/application.properties
shop.other = (not set)
$ curl -i http://localhost:8080/a.txt
HTTP/1.1 200
Content-Type: text/plain
served from static/
$ curl -i http://localhost:8080/b.txt
HTTP/1.1 200
Content-Type: text/plain
served from public/
$ curl -i http://localhost:8080/c.txt
HTTP/1.1 200
Content-Type: text/plain
served from resources/
$ curl -i http://localhost:8080/d.txt
HTTP/1.1 200
Content-Type: text/plain
served from META-INF/resources/
$ curl -i http://localhost:8080/e.txt
HTTP/1.1 404
Content-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.txt
HTTP/1.1 404

3名前ではなくアノテーションで見分ける(模型)

クラスの名前や置き場所を見ずに、の有無だけで部品を選ぶ、という見分け方の模型です。 そのものではありませんが、考え方は同じです。Banana という名前でも印があれば登録され、OrderService という名前でも印が無ければ無視されます。

Java

4起動クラスを隣へ移すと、エラー無しで 404 になる

起動クラスだけを com.example.shop.app に移した変種です。controller や service は app の配下ではなく隣にあるので、走査の範囲から外れます。ログには Started と出て起動は成功しており、エラーも警告もありません。リクエストして初めて 404 で気づきます。

変種 outside の tree、起動ログ、応答(Boot 4.1.1 / JDK 25)コマンド出力
$ 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/1
HTTP/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/

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