依存性注入(Dependency Injection、DI)には主に三つの実装方法があります。
1. コンストラクタ注入
public class OrderService {
private PaymentProcessor paymentProcessor;
public OrderService(PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
public void processOrder(Order order) {
paymentProcessor.processPayment(order.getAmount());
System.out.println("注文が正常に処理されました");
}
}
public class Application {
public static void main(String[] args) {
PaymentProcessor processor = new CreditCardProcessor();
OrderService service = new OrderService(processor);
service.processOrder(new Order(100.0));
}
}
この方式では、オブジェクトがインスタンス化される際に必要な依存関係がすべて提供されます。これにより、オブジェクトの不変性が保証され、必須の依存関係が欠落するリスクを防ぎます。
- Setterメソッド注入
public class OrderService {
private PaymentProcessor paymentProcessor;
public void setPaymentProcessor(PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
public void processOrder(Order order) {
paymentProcessor.processPayment(order.getAmount());
System.out.println("注文が正常に処理されました");
}
}
public class Application {
public static void main(String[] args) {
PaymentProcessor processor = new PayPalProcessor();
OrderService service = new OrderService();
service.setPaymentProcessor(processor);
service.processOrder(new Order(200.0));
}
}
この方式では、依存関係はオブジェクトの作成後に設定できます。これにより、柔軟性が向上し、実行時に依存関係を変更できるようになります。
- インターフェース注入
public interface Injectable {
void setDependency(Object dependency);
}
public class OrderService implements Injectable {
private PaymentProcessor paymentProcessor;
@Override
public void setDependency(Object dependency) {
if (dependency instanceof PaymentProcessor) {
this.paymentProcessor = (PaymentProcessor) dependency;
}
}
public void processOrder(Order order) {
paymentProcessor.processPayment(order.getAmount());
System.out.println("注文が正常に処理されました");
}
}
public class Application {
public static void main(String[] args) {
PaymentProcessor processor = new CryptocurrencyProcessor();
OrderService service = new OrderService();
service.setDependency(processor);
service.processOrder(new Order(300.0));
}
}
この方式では、依存関係の注入を明示的なインターフェースを通じて行います。しかし、この方法は現在ではあまり一般的ではなく、他の注入方法に取って代わられつつあります。
Springコンテナ
1.Spring IOCコンテナがBean設定を読み込みBeanインスタンスを作成する前に、コンテナ自体のインスタンス化が必要です。コンテナがインスタンス化された後にのみ、IOCコンテナからインスタンスを取得して使用できます。
// Springコンテナオブジェクトの作成。ApplicationContextはIOCコンテナであり、実際にはインターフェースです // ClassPathXmlApplicationContext: ApplicationContextインターフェースの実装クラスで、クラスパス下から設定ファイルを読み込みます ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
2.Springは二種類のIOCコンテナ実装を提供しています:
- BeanFactory:IOCコンテナの基本的な実装。
- ApplicationContext:より多くの高度な機能を提供し、BeanFactoryのサブクラスです。
- BeanFactoryはSpringフレームワークの基盤であり、Spring自体に向けられています。一方、ApplicationContextはSpringフレームワークを使用する開発に向けられており、ほとんどのアプリケーションではBeanFactoryではなくApplicationContextが使用されます。
- 使用方法に関わらず、設定ファイルは同じです。
ApplicationContext
1.ApplicationContextはインターフェースであり、主に二つの実装クラスがあります:
- ClassPathXmlApplicationContext:クラスパスから設定ファイルを読み込みます。
- FileSystemXmlApplicationContext:ファイルシステムから設定ファイルを読み込みます。
2.ConfigurableApplicationContextはApplicationContextを拡張し、refresh()メソッドとclose()メソッドという二つの主要なメソッドを追加しています。これにより、ApplicationContextにコンテキストの起動、更新、およびシャットダウン機能が備わります。
3.ApplicationContextは初期化時にすべてのシングルトンBeanをインスタンス化します。
4.WebApplicationContextはWebアプリケーション専用に用意されており、WEBルートディレクトリからの相対パスで初期化操作を実行できます。
Springにおける依存性注入の三つの方法
1.Springは三種類の依存性注入方式をサポートしています:
- プロパティ注入(最も一般的)
- コンストラクタ注入
- ファクトリメソッド注入(ほとんど使用されず、非推奨のためここでは説明しません)
2.プロパティ注入
- プロパティ注入とは、Beanのプロパティ値や依存オブジェクトをsetメソッドを通じて注入する方法です。
- プロパティ注入は<property>要素を使用し、name属性でBeanのプロパティ名を指定し、value属性またはvalueサブノードでプロパティ値を指定します。
- プロパティ注入は開発において最も一般的に使用される注入方式です。
<!-- id: IOCコンテナから取り出すための一意の識別子で、通常はクラス名の最初の文字を小文字にしたものです class: Beanの完全修飾クラス名。リフレクションを通じてBeanを作成するため、Beanには引数なしのコンストラクタが必要です property: プロパティの設定を表します。nameはsetメソッドを呼び出します(setメソッドの名前は一致させる必要があります)、valueは値を設定します --> <bean id="userService" class="com.example.UserService"> <property name="dataSource" ref="dataSource"></property> </bean>
3.コンストラクタ注入
- コンストラクタを通じてBeanのプロパティ値や依存オブジェクトを注入します。これにより、Beanインスタンスがインスタンス化された直後に使用できることが保証されます。
- コンストラクタ注入は<constructor-arg>要素でプロパティを宣言しますが、<constructor-arg>にはname属性がありません。
- コンストラクタ注入を使用してプロパティ値を指定する場合、パラメータの位置とタイプを指定して、オーバーロードされたコンストラクタを区別できます。
<!-- id: IOCコンテナから取り出すための一意の識別子で、通常はクラス名の最初の文字を小文字にしたものです class: Beanの完全修飾クラス名。リフレクションを通じてBeanを作成するため、Beanには引数なしのコンストラクタが必要です constructor-arg: valueは値の設定、indexはパラメータの位置、typeはパラメータのタイプです --> <bean id="databaseConfig" class="com.example.DatabaseConfig"> <constructor-arg value="localhost" index="0"></constructor-arg> <constructor-arg value="3306" index="1"></constructor-arg> <constructor-arg value="mydatabase" index="2"></constructor-arg> </bean>