0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Spring Boot起動中に出た例外をFailureAnalyzerでつかむ

Last updated at Posted at 2020-01-15

経緯

こちらを参照
https://qiita.com/ShassBeleth/items/476436b7c81fe81ddbb2

まぁ指定のポートがすでに使われてた場合のExceptionは
もともとSpring Bootに用意されてるんだけどね

上書きもできるし追加もできるよっていう話

環境

Spring Boot 2.2.2.RELEASE - 2.2.4.RELEASE
Kotlin 1.3.61
Gradle

環境は以下の記事のまんま

Spring Boot側が用意してくれてるFailureAnalyzer

例外つかむにはAbstractFailureAnalyzerを継承する必要がある
検索かけて出てきたクラスがこれ

image.png

全部で17個
さらにそれぞれのクラスを継承するかもしれないからもっとあるかも

ポートが既に使われてた時に呼ばれるExceptionはPortInUseException
それをつかむのがPortInUseFailureAnalyzer

PortInUseFailureAnalyzer.java
class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> {

	@Override
	protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {
		return new FailureAnalysis("Web server failed to start. Port " + cause.getPort() + " was already in use.",
				"Identify and stop the process that's listening on port " + cause.getPort() + " or configure this "
						+ "application to listen on another port.",
				cause);
	}

}

中のクラスはこんな感じ

適当に裏でポート8080使っといて
image.png

Boot Runでアプリを起動すると・・・

image.png

こんな感じ

FailureAnalyzerにあるDescriptionとActionがログに書き込まれてるっていうね

Spring Bootが用意してるFailureAnalyzerを独自のものに書き換える

正直おすすめはできない

MyPortInUseFailureAnalyzer.kt
class MyPortInUseExceptionFailureAnalyzer : AbstractFailureAnalyzer<PortInUseException>() {
    override fun analyze(rootFailure: Throwable, cause: PortInUseException): FailureAnalysis {
        return FailureAnalysis(
                cause.message,
                "Port already in use!!!",
                cause
        )
    }
}

AbstractFailureAnalyzer<PortInUseException>を継承したクラスを作っておく

resources/META-INF/フォルダ配下にspring.factoriesファイルを作って

resources/META-INF/spring.factories
org.springframework.boot.diagnostics.FailureAnalyzer =\
  com.example.spring.boot.web.failure.analyzer.MyPortInUseFailureAnalyzer 

その中身はこんな感じ
これで登録OK

また適当にポート8080を裏で使っておいてからBoot Runすると

image.png

上書きできましたー

おすすめしないっていうのも例外時に出力される情報を変更できちゃうので、実際に例外が発生したときに何があったかわからなくなるから
出力される内容は変えずに処理をはさんだりとかするのがいいのかな・・・?

FailureAnalyzerのカスタマイズの使い道としては以下の方が実用的かも

独自のExceptionをFailureAnalyzerでつかむ

SampleFailureAnalyzer.kt
/**
 * 独自の例外
 */
class SampleException(message: String?) : RuntimeException(message)

/**
 * カスタムFailureAnalyzerのサンプル
 * アプリ起動中に発生したSampleExceptionをつかむ
 */
class SampleFailureAnalyzer : AbstractFailureAnalyzer<SampleException>() {
    override fun analyze(rootFailure: Throwable, cause: SampleException): FailureAnalysis {
        return FailureAnalysis(
                cause.message,
                "Sample Exception!",
                cause
        )
    }
}

こんな感じに独自の例外を作っておいて、それをつかむFailureAnalyzerを作成しておく

spring.factoriesはこんな感じ

resources/META-INF/spring.factories
org.springframework.boot.diagnostics.FailureAnalyzer =\
  com.example.spring.boot.web.failure.analyzer.MyPortInUseFailureAnalyzer ,\
  com.example.spring.boot.web.failure.analyzer.SampleFailureAnalyzer

複数のFailureAnalyzerを登録することもできます

で、作ったSampleFailureAnalyzerがちゃんとつかめるか確認したいから
以下を適当に作っておく

SampleFailureAnalyzer.kt
/**
 * アプリ起動中に読み込まれるサンプルComponent
 */
@Component
class SampleComponent {
    fun run() {
        throw SampleException("exception!")
    }
}

/**
 * リフレッシュ時にイベント発火するListenerクラス
 */
@Component
class SampleApplicationListener : ApplicationListener<ContextRefreshedEvent?> {

    @Autowired
    private val sampleComponent: SampleComponent? = null

    /**
     * リフレッシュ時にSampleComponentのrunを実行する(例外を発生させる)
     */
    override fun onApplicationEvent(event: ContextRefreshedEvent) {
        sampleComponent!!.run()
    }

}

  1. リフレッシュ時にSampleApplicationListenerのonApplicationEventが呼ばれる
  2. sampleComponentのrunが呼ばれる
  3. runの中でExceptionが発生する

って感じ
これでアプリ起動時にエラーが発生するようになりました

実行してみると

image.png

ちゃんとメッセージ出せてます!

spring.factoriesを登録していない場合はスタックトレースが表示されます

image.png

まとめ

  • FailureAnalyzerでアプリ起動中の例外もつかめる!
  • 既にSpring Bootが用意してくれてるものも上書きできる!
  • 自分で作った例外もつかめる!

スタックトレースのほうがわかりやすい場合もあるし、一概にすべてのExceptionをつかんだほうがいいとは言えないのかな・・・?
でも把握できてるExceptionかどうか、発生しうる例外かどうかの判断はできるし、まぁまぁ便利だなとは思う

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?