[速習] Spring 第2回 ソフトウェアのプロフェッショナルへの道 (SpringにおけるDI/SpringにおけるAOP)

![c02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3521573/b852ac8a-c0f8-4529-1075-b2386ac2c51c.png)

https://qiita.com/ShigemoriMasato/items/c0e015098730d93a188b

前回の記事では、Springの全体像とその魅力、そしてWebアプリケーションの基本について説明しました。今回は、Springの中心的な特性である依存性注入(Dependency Injection, DI)とAOP(Aspect Oriented Programming)について深堀りしていきます。

## SpringにおけるDI

DI[^1]とは、オブジェクト[^2]間の依存関係を外部から注入する手法で、オブジェクトの生成とそのライフサイクルの管理をSpringのコンテナ[^3]が担当します。このDIの仕組みにより、コードの結合度を下げ、テストや再利用が容易な設計を実現することが可能になります。

```mermaid
graph BT
  subgraph "Without Dependency Injection"
    ProductControllerWithoutDI[ProductController] -->|creates & manages| TestProductServiceWithoutDI[TestProductService]
    TestProductServiceWithoutDI -->|creates & manages| TestProductRepositoryWithoutDI[TestProductRepository]
  end

  subgraph "With Dependency Injection"
    ProductControllerWithDI[ProductController] -->|depends on| TestProductServiceWithDI[TestProductService]
    FactoryWithDI[Factory] -.->|injects| TestProductServiceWithDI
    TestProductServiceWithDI -->|depends on| TestProductRepositoryWithDI[TestProductRepository]
    FactoryWithDI -.->|injects| TestProductRepositoryWithDI
  end
```

これにより、各オブジェクトは自身の主要な業務に集中することができ、コードの可読性と保守性が向上します。

具体的には、オブジェクトは他のオブジェクトの生成やライフサイクルの管理から解放され、それぞれが自己の役割に専念できます。これは、ソフトウェア開発における多くの課題を解決します。

```mermaid
graph LR
  subgraph "With DI Container"
    FactoryWithContainer[Factory] -->|creates & injects| ProductControllerWithContainer[ProductController]
    ProductControllerWithContainer -->|depends on| TestProductServiceWithContainer[TestProductService]
    ProductControllerWithContainer -->|depends on| ProdProductServiceWithContainer[ProdProductService]
    FactoryWithContainer -.->|creates & injects| TestProductServiceWithContainer
    FactoryWithContainer -.->|creates & injects| ProdProductServiceWithContainer
    TestProductServiceWithContainer -->|depends on| TestProductRepositoryWithContainer[TestProductRepository]
    ProdProductServiceWithContainer -->|depends on| ProdProductRepositoryWithContainer[ProdProductRepository]
    FactoryWithContainer -.->|creates & injects| TestProductRepositoryWithContainer
    FactoryWithContainer -.->|creates & injects| ProdProductRepositoryWithContainer
  end
```

DIの主な利点は、コードの再利用性とテスト性を向上させ、コード間の結合度を下げることです。これにより、プログラムの一部を容易に切り替えることが可能になります。例えば、テスト環境と本番環境で使用するオブジェクトを切り替える、あるいは特定の機能の実装を変更するといったケースで、DIはその力を発揮します。そのため、DIはソフトウェアの設計と開発において非常に重要な概念となっています。

```mermaid
classDiagram
  class ProductController {
    +execute(): void
  }
  class TestProductService {
    <<interface>>
    +execute(): void
  }
  class ProdProductService {
    <<interface>>
    +execute(): void
  }
  class TestProductRepository {
    +query(): void
  }
  class ProdProductRepository {
    +query(): void
  }
  class DIContainer {
    +createAndInject(): void
  }
  ProductController --> DIContainer: depends on
  DIContainer --> TestProductService: creates & injects
  DIContainer --> ProdProductService: creates & injects
  TestProductService --> TestProductRepository: depends on
  ProdProductService --> ProdProductRepository: depends on
  DIContainer --> TestProductRepository: creates & injects
  DIContainer --> ProdProductRepository: creates & injects
```

DIは、Springのアノテーションである`@Autowired`をはじめとするアノテーションを使用し、依存性を自動で注入します。注入はコンストラクタ、セッター、フィールドに対して行うことが可能で、これによりコンポーネントのゆるやかな結合が実現されます。また、テスト時のモックオブジェクトの注入にも利用され、テストの効率化と信頼性の向上に貢献します。これらの特性により、DIはソフトウェアの開発をより効率的で品質の高いものにします。

SpringのコンテナがDIの中心的な役割を果たします。具体的には、コンテナは依存関係を解決し、オブジェクトがインスタンス化[^4]されるタイミングで依存性を注入します。

```mermaid
classDiagram
  class ProductController {
    +execute(): void
  }
  class TestProductService {
    <<interface>>
    +execute(): void
  }
  class ProdProductService {
    <<interface>>
    +execute(): void
  }
  class TestProductRepository {
    +query(): void
  }
  class ProdProductRepository {
    +query(): void
  }
  class DIContainer {
    +createAndInject(): void
  }
  class SingletonScope {
  }
  class PrototypeScope {
  }
  ProductController --> DIContainer: depends on
  DIContainer --> TestProductService: creates & injects
  DIContainer --> ProdProductService: creates & injects
  TestProductService --> TestProductRepository: depends on
  ProdProductService --> ProdProductRepository: depends on
  DIContainer --> TestProductRepository: creates & injects
  DIContainer --> ProdProductRepository: creates & injects
  SingletonScope --> DIContainer: manages
  SingletonScope --> ProductController: manages
  SingletonScope --> TestProductService: manages
  SingletonScope --> ProdProductService: manages
  PrototypeScope --> TestProductRepository: manages
  PrototypeScope --> ProdProductRepository: manages
```

また、SpringのコンテナはBeanのスコープを管理します。代表的なのが、アプリケーションのライフサイクルに沿って一度だけインスタンス化されるシングルトンスコープと、毎回新しいインスタンスが生成されるプロトタイプスコープです。このスコープの違いにより、Beanの振る舞いを柔軟に定義することができます。

さらに、AOP[^5]のプロキシ[^6]も注入対象となり、AOPとDIが連携することで、Springの柔軟性と強力な機能が実現されます。このように、DIはSpringの基盤となる特性であり、Springの強力な機能の多くはこのDIの仕組みによって実現されています。

https://note.com/happyodangoo/n/ne5e69c9ff1e0

## SpringにおけるAOP

次に、Springのもう一つの重要な特性であるAOP(Aspect Oriented Programming)について詳しく見ていきましょう。AOPは、プログラムの本質的な部分と付加的な部分を分離する手法で、これによりコードのモジュール性と再利用性が向上します。SpringはAOP Allianceの仕様に準拠したAOP機能を提供し、これにより横断的な処理を効率的に管理することが可能になります。

AOPの主な利点は、横断的な処理をまとめて定義できることです。これにより、コードの重複を避け、可読性と保守性を向上させることができます。例えば、ログ出力やトランザクション管理など、複数のクラスやメソッドで共通して行う処理を、アスペクト[^7]として定義し、必要な場所で適用することができます。このように、AOPはソフトウェアの開発において、コードの管理と再利用を効率的に行うための重要な手段となります。

AOPは、主に`@Aspect`アノテーションとポイントカットを使用し、アスペクトおよびアドバイス[^8]を定義することで適用が可能です。

```mermaid
classDiagram
direction LR
class ApplicationCode{
+ call()
}

class Aspect{
+ beforeAdvice()
+ afterAdvice()
}

class Target{
+ targetMethod()  
}

class Proxy{
+ delegate()
}

Proxy --> Aspect : uses(beforeAdvice)
Proxy --> Aspect : uses(afterAdvice)
Proxy ..> ApplicationCode : uses
ApplicationCode --> Proxy : uses
Proxy --> Target : delegates
```

このアスペクトとアドバイスの定義により、横断的な処理の振る舞いと適用範囲を柔軟に制御することができます。さらに、Springでは、AspectJのアノテーションもサポートされており、より高度なAOPの表現が可能となっています。これらの特性により、AOPはソフトウェアの設計と開発において高度なモジュール性と再利用性を提供します。

AOPの仕組みは、アスペクトと呼ばれるモジュールを定義し、それを特定の「ジョインポイント」[^9]（アドバイスが適用される場所）に適用することで、プログラムの本質的な部分と付加的な部分を分離します。これにより、DIされたBean[^10]に柔軟に横断処理を適用することが可能になります。このAOPの仕組みにより、Springは高度なモジュール性と再利用性を実現し、大規模な開発プロジェクトでも効率的なコード管理を可能にします。特に、DIとAOPが連携することで、Springはその強力な機能をさらに拡張し、より複雑なソフトウェアの開発を効率的に行うことが可能となります。

https://note.com/happyodangoo/n/nafb18cc59648

## おわりに

今回の記事では、Springの中心的な特性であるDIとAOPについて詳しく解説しました。これらの特性は、Springが提供する強力な機能の一部であり、これらを理解し適切に利用することで、効率的で保守性の高いコードを書くことが可能となります。特に、大規模な開発プロジェクトでは、これらの特性がコードのモジュール性と再利用性を向上させ、開発の効率化と品質保証に大いに貢献します。

この記事が、あなたのSpring学習の一助となり、より効率的で保守性の高いコードを書くための道筋を示すことができれば幸いです。また、今回学んだ知識が、あなたの開発スキルを新たなレベルに引き上げる一助となることを願っています。

https://qiita.com/ShigemoriMasato/items/4b6e69c98c6371698ff1

[^1]: DI(Dependency Injection) - オブジェクト間の依存関係を外部から注入することで、オブジェクトの生成とライフサイクルの管理をコンテナが行う設計パターン。
[^2]: オブジェクト - プログラムの中でデータや処理を一まとめにしたもの。オブジェクト指向プログラミングにおける基本的な構成要素。
[^3]: コンテナ - アプリケーションのオブジェクトのライフサイクルと設定を管理するもの。Springでは、DIコンテナと呼ばれる。
[^4]: インスタンス化 - クラスからオブジェクトを生成すること。具体的なデータを持った状態のオブジェクトを作り出す行為。
[^5]: AOP(Aspect Oriented Programming) - 横断的な処理を分離・モジュール化することで、コードの再利用性と可読性を向上させるプログラミングパラダイム。
[^6]: プロキシ - あるオブジェクトの代理となって動作するオブジェクト。元のオブジェクトの振る舞いを変更したり、機能を追加したりする。
[^7]: アスペクト - AOPにおいて、横断的な処理をまとめたモジュール。アドバイスとポイントカットを組み合わせて定義される。
[^8]: アドバイス - AOPにおいて、横断的な処理そのものを表す。前処理や後処理、例外処理など、様々なタイプのアドバイスが存在する。
[^9]: ジョインポイント - AOPにおいて、アドバイスが適用される具体的な場所。メソッド呼び出しや例外発生など、様々な場所を指定できる。
[^10]: Bean - Springに管理されるオブジェクトのこと。Springのコンテナによってインスタンス化、組み立て、管理される。