Spring Core Concepts

この文書(ぶんしょ) は Spring Framework の核心概念(かくしんがいねん)学習順序(がくしゅうじゅんじょ)(したが) って整理(せいり) しています。


Spring と JakartaEE

Spring は複数(ふくすう) の JakartaEE (J2EE) 標準(ひょうじゅん)統合(とうごう) しています:

  1. Servlet API (JSR 340)
  2. WebSocket API (JSR 356)
  3. Concurrency Utilities (JSR 236)
  4. JSON Binding API (JSR 367)
  5. Bean Validation (JSR 303)
  6. JPA (JSR 338)
  7. JMS (JSR 914)
  8. Dependency Injection (JSR 330)Common Annotations (JSR 250)支援(しえん)

Spring IoC

Inversion of Control: オブジェクトの作成(さくせい)依存関係管理(いぞんかんけいかんり)権限(けんげん) を、開発者(かいはつしゃ) から Spring コンテナに移転(いてん) すること。

**制御(せいぎょ)反転(はんてん) **:オブジェクトの制御権(せいぎょけん) をサードパーティのコンテナ(IoC コンテナ)に移転(いてん) するという設計思想(せっけいしそう) です。

IoC コンテナの種類

  • BeanFactory: 基本(きほん) インターフェース、高度(こうど)設定(せってい) メカニズムを提供(ていきょう)
  • ApplicationContext: BeanFactory のサブインターフェース、AOP 統合(とうごう) 、メッセージ処理(しょり) 、イベント発行(はっこう) などのエンタープライズ機能(きのう)追加(ついか)

Spring DI

Dependency Injection: IoC を実現(じつげん) する具体的(ぐたいてき)技術(ぎじゅつ)

  • オブジェクトは自身(じしん)依存関係(いぞんかんけい)作成(さくせい) せず、コンテナによって注入(ちゅうにゅう) されます(制御(せいぎょ)反転(はんてん) )。
  • 利点(りてん) : テストが容易(ようい) (モックオブジェクトの注入(ちゅうにゅう) )、疎結合(そけつごう)構成(こうせい)柔軟性(じゅうなんせい)
**依存性注入(いぞんせいちゅうにゅう) **:被依存(ひいぞん) オブジェクトを(IoCコンテナを(かい) して)受動的(じゅどうてき)受信(じゅしん) オブジェクト(ちゅう)注入(ちゅうにゅう) すること。

注入方式

  • Setter 注入(ちゅうにゅう) : setXXX() メソッドを使用(しよう)
  • Constructor 注入(ちゅうにゅう) : コンストラクタを使用(しよう)
  • 自動(じどう) ワイヤリング (Autowire):
    • byType: 属性(ぞくせい)(かた)検索(けんさく)
    • byName: 属性名(ぞくせいめい) (Bean ID)で検索(けんさく)

Java EE 6 CDI vs Spring DI

機能(きのう)Java EE 6 CDISpring DI
標準化(ひょうじゅんか)Java 標準(ひょうじゅん) API (CDI 仕様(しよう) )。サードパーティフレームワーク。
アノテーションアノテーション(すう)(すく) なく、システムが単純(たんじゅん)アノテーション種類(しゅるい)豊富(ほうふ)強力(きょうりょく) だが複雑(ふくざつ)
構成(こうせい)硬直的(こうちょくてき) だが理解(りかい) しやすい。柔軟(じゅうなん) な XML/Java 構成(こうせい)

Spring Bean

  • Spring IoC コンテナによって管理(かんり) されるすべての Java オブジェクト。

Bean Scope

  • Singleton: グローバルシングルトン。
  • Prototype: 要求(ようきゅう) ごとに(あたら) しいインスタンスを作成(さくせい)
  • Web 専用(せんよう) : Request, Session, Application, WebSocket

Spring Bean Lifecycle

4 つの主要段階(しゅようだんかい) :

  1. 実体化(じったいか) (Instantiation)
  2. 属性設定(ぞくせいせってい) (Populate)
  3. 初期化(しょきか) (Initialization)
  4. 破棄(はき) (Destruction)

簡易フローチャート

  flowchart LR
	c[Constructor]
	a[Autowired]
	p[PostConstruct]
	i[InitializingBean]
	app[ApplicationRunner]
	cli[CommandLineRunner]
	c --> a --> p --> i --> app --> cli

詳細フローチャート

  flowchart TB
    subgraph Instantiation_実体化
    	Constructor
    end
    subgraph Population_Of_Properties_属性設定
    	Setter_Injection
    end
    subgraph BeanNameAware_Bean名設定
		setBeanName
    end
	subgraph setBeanFactory_工場設定
		BeanFactoryAware
    end
	subgraph ApplicationContext_文脈設定
		setApplicationContext
    end
	subgraph BeanPostProcessor_前処理
		postProcessBeforeInitalization
    end
	subgraph PostConstruct_注釈初期化
		init_method
    end
	subgraph InitializingBean_面初期化
		afterPropertiesSet
    end
	subgraph Custom_Initialization_独自初期化
		custom_init_method
    end
	subgraph postProcess_AfterIntialization_後処理
		p_BeanPostProcessor
    end
	subgraph PreDestroy_予備破棄
		destroy_method
    end
	subgraph DisposableBean_面破棄
		destroy_method
    end
	subgraph Custom_Destruction_独自破棄
		Custom_Destroy_Method
	end

	Instantiation_実体化 ==> Population_Of_Properties_属性設定 ==> BeanNameAware_Bean名設定
	BeanNameAware_Bean名設定 ==> setBeanFactory_工場設定 ==> ApplicationContext_文脈設定
	ApplicationContext_文脈設定 ==> BeanPostProcessor_前処理 ==> PostConstruct_注釈初期化 ==> InitializingBean_面初期化
	InitializingBean_面初期化 ==> Custom_Initialization_独自初期化 ==> postProcess_AfterIntialization_後処理
	postProcess_AfterIntialization_後処理 ==> PreDestroy_予備破棄 ==> DisposableBean_面破棄
	DisposableBean_面破棄 ==> Custom_Destruction_独自破棄

ApplicationContextAware インターフェース

このインターフェースを実装(じっそう) する Bean は、起動時(きどうじ)ApplicationContext への参照(さんしょう)取得(しゅとく) できます。

  • Use Case (使用例(しようれい) )
    • イベントリスナーで、ビジネスロジックに(もと) づいて Bean を動的(どうてき)取得(しゅとく) する必要(ひつよう) がある場合(ばあい)循環依存(じゅんかんいぞん)() けるためなど)。
    • ユーティリティクラス(Helper Class)で、静的(せいてき) メソッドから Spring 管理(かんり) のサービスにアクセスする場合(ばあい)
@Component
public class SpringContextHolder implements ApplicationContextAware {
	private static ApplicationContext appContext;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		appContext = applicationContext;
	}

	public static ApplicationContext getApplicationContext() {
		checkApplicationContext();
		return appContext;
	}

	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		checkApplicationContext();
		return (T) appContext.getBean(name);
	}

	@SuppressWarnings("unchecked")
	public static <T> T getBean(Class<T> clazz) {
		checkApplicationContext();
		Map beanMaps = appContext.getBeansOfType(clazz);
		if (beanMaps != null && !beanMaps.isEmpty()) {
			return (T) beanMaps.values().iterator().next();
		} else {
			return null;
		}
	}

	private static void checkApplicationContext() {
		if (appContext == null) {
			throw new IllegalStateException("applicationContext has not been injected yet.");
		}
	}
}

Spring AOP

プロキシパターンを使用(しよう) して、ログやセキュリティなどの機能(きのう)横断的(おうだんてき)適用(てきよう) します。ビジネスロジックと基盤(きばん) インフラの関心事(かんしんじ)分離(ぶんり)

  flowchart LR
	0((AOP)) --> 1([Around 前置処理]) --> 2([Before]) --> 3[Target Object] --> 4([AfterReturning]) --> 5([After]) --> 6([Around 後置処理])

CGLIB プロキシ

Code Generation Library

CGLIB は高性能(こうせいのう) なコード生成(せいせい) ライブラリです。Spring AOP では、ターゲットオブジェクトがインターフェースを実装(じっそう) していない場合(ばあい) 、Spring は自動的(じどうてき) に CGLIB を使用(しよう) してプロキシオブジェクトを作成(さくせい) します。ターゲットクラスを継承(けいしょう) してプロキシを実装(じっそう) するため、final クラスやメソッドはプロキシできません。


Transaction

Propagation

@Transactional(propagation = Propagation.REQUIRED)

パラメータ説明(せつめい)
REQUIREDデフォルト既存(きそん) があれば参加(さんか) 、なければ新規作成(しんきさくせい)
SUPPORTS既存(きそん) があれば参加(さんか) 、なければ() トランザクションで実行(じっこう)
MANDATORYトランザクション(ない) での実行(じっこう)必須(ひっす)() ければ例外(れいがい) をスロー。
REQUIRES_NEW現在(げんざい) のを中断(ちゅうだん) し、完全(かんぜん)独立(どくりつ) したものを作成(さくせい)
NOT_SUPPORTED() トランザクションで実行(じっこう)現在(げんざい) のは一時停止(いちじていし)
NEVERトランザクション(ない) での実行(じっこう)禁止(きんし)() れば例外(れいがい) をスロー。
NESTEDネストされたトランザクション(() のロールバックは(おや)影響(えいきょう) しないが、(おや) のロールバックは()影響(えいきょう) )。

動作比較例

  • REQUIRED: A メソッドが B メソッドを()() す、両者(りょうしゃ)(おな) じトランザクション(ない) 。B がエラーなら全体(ぜんたい) ロールバック。
  • REQUIRES_NEW: A メソッドが B メソッドを()() す、B は独立(どくりつ) トランザクションを開始(かいし) 。B のロールバックは A に影響(えいきょう) しない。
  • NESTED: A メソッドが B メソッドを()() す、B は A の() トランザクション。B のエラーは個別(こべつ) にロールバック可能(かのう) (Catch 必要(ひつよう) )。

適用シナリオ (Use Case)

  1. 独立(どくりつ) ログ記録(きろく) : ビジネス失敗(しっぱい) でもログ記録(きろく)必要(ひつよう)場合(ばあい) 、ログサービスは REQUIRES_NEW設定(せってい)
  2. 複雑(ふくざつ) なビジネス補償(ほしょう) : 注文(ちゅうもん) メインフローとポイント付与(ふよ) 、ポイント失敗(しっぱい)注文(ちゅうもん)失敗(しっぱい) すべきでない場合(ばあい)NESTED + Try-Catch を使用(しよう)
@Transactional(propagation = Propagation.REQUIRED)
public void mainProcess() {
    orderService.saveOrder(); // 成功
    try {
        logService.log(); // REQUIRES_NEW に設定、A がロールバックしてもログは残る
    } catch (Exception e) {}
}

WebSocket API

  flowchart TB
	HTTP握手攔截器[HttpSessionHandshakeInterceptor]
	HTTP握手前[beforeHandshake]
	HTTP握手後[afterHandshake]
	WssText處理器[TextWebScoketHandler]
	是否支持內容拆分[supportPartialMessages]
	Wss連線建立後[afterConnectionEstablished]
	Wss連線關閉後[afterConnectionClosed]

	HTTP握手攔截器 --> HTTP握手前 --> HTTP握手後 --> WssText處理器 --> 是否支持內容拆分 --> Wss連線建立後 --> Wss連線關閉後