LoginSignup
7
4

More than 3 years have passed since last update.

BeanとDIについて

Last updated at Posted at 2019-09-27

  • 依存性とDI
    • 依存性とは
    • DI(依存性の注入)とは
    • 「依存している状態」とは
    • 依存状態の問題点
    • 依存性の解決
  • Bean構成ファイル(XML)による解決
    • ファイルの作成
    • ファイルの編集
    • タグの編集内容
    • クラスの編集
    • ApplicationContextとは
  • インターフェース化する
    • インターフェースの作成
    • 作成/変更されたクラス
    • 別のBeanクラスの設定
  • Bean構成ファイル(XML)を用いない解決
    • Bean構成クラスの作成
    • クラスの編集
    • AnnotationConfigApplicationContextとは
    • アノテーションについて

依存性とDI

依存性とは

  • それぞれのコンポーネントの固有の設定などを意味する

ある程度の規模の開発を行う場合、汎用的な部品をコンポーネント化して利用することになります。このとき、特定のコンポーネントを作成し、設定する処理がコード内に直接書かれていると、後々面倒なことになります。

  • 特定のデータや設定が本来汎用的であるコンポーネントと密接な関係を持つことで、コンポーネント自体の柔軟性が失われてしまうことが問題

DI(依存性の注入)とは

  • DI = Dependency Injection

Dependency Injection (依存性注入) とは、あるクラスが別のクラスをインスタンス変数に持つなどして利用 (依存) している場合に、インスタンス変数の設定 (依存性の解決) をクラス内で行うのではなく、外部から設定 (注入) するという考え方。

設定を利用から分離する(the principle of separating configuration from use)」という考え方をコンポーネント設計のための1つの原則としている。

  • 上記で説明した「あるクラスの処理が、他の特定クラスに依存している状態を」解消するのがDIの目的

DIコンテナ.jpg
DIコンテナ2.jpg

「依存している状態」とは

  • SampleBean.java
public class SampleBean {

  private Date date;
  private String message;

  public SampleBean() {
    this.date = new Date();
  }

  public SampleBean(String message) {
    this();
    this.message = message;
  }

  public Date getDate() {
    return date;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  @Override
  public String toString() {
    return "Date = " + date + " & Message = " + message;
  }
} 
  • App.java
public class App {

  public static void main(String[] args) {
    SampleBean bean = new SampleBean("Hello World!");
    System.out.println(bean);
  }
}
  • 実行結果
Date = Wed Sep 25 15:00:00 JST 2019 & Message = Hello World!

依存状態の問題点

  • messageに設定する値を変更する場合はソースコードを直接書き換え、再コンパイルする必要がある

  • UTについても、クラス内で設定された値をテストクラスに記述する必要がある

→ 「そのBeanのためだけにしか役に立たないコード」を記述することで柔軟性が失われている

依存性の解決

  • 以下2つの処理をApp内から切り離す
  1. SampleBeanのインスタンスを生成する処理
  2. messageに値を設定する処理

Bean構成ファイル(XML)による解決

  • XMLの情報を元にインスタンスを自動生成し、プログラム内で利用できるようにする

ファイルの作成

  1. STSで <File> - <New> - <Spring Bean ConfigurationFile>を選択
    スクリーンショット 2019-09-27 0.45.56.png

  2. ファイルの保存場所とファイル名を指定
    スクリーンショット 2019-09-27 0.49.13.png

  3. XSD(XMLスキーマ定義)の名前空間を設定 = Bean構成ファイルで記述する内容のためのXSDを設定
    スクリーンショット 2019-09-27 0.59.54.png

ファイルの編集

1.初期状態

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">


</beans>

2.SampleBeanクラスのインスタンス設定をbean.xmlに追加

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="sample" class="jp.spring.sample.SampleBean">
    <property name="message" value="this is sample bean!">
    </property>
  </bean>
</beans>

もしくは

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="sample" class="jp.spring.sample.SampleBean">
    <constructor-arg type="String" name="message" value="this is sample bean!">
    </constructor-arg>
  </bean>
</beans>

タグの編集内容

  • beanタグ
<bean id="インスタンス名" class="クラスのパス">
  • propertyタグ
<property name="プロパティ名" value="値">
  • constructor-argタグ
<constructor-arf type="タイプ名" name="引数名" value="値">

クラスの編集

  • App.java
public class App {

  private static ApplicationContext app;

  public static void main(String[] args) {
    app = new ClassPathXmlApplicationContext("bean.xml");
    SampleBean bean = (SampleBean)app.getBean("sample");
    System.out.println(bean);
  }
}
  • 実行結果
Date = Wed Sep 25 15:00:00 JST 2019 & Message = this is sample bean!

ApplicationContextとは

private static ApplicationContext app;
  • 従来のBeanFactoryを拡張したもの
  • メモリの使用量に厳しい制限がある場合を除き BeanFactory よりも ApplicationContext を使用することが推奨されている

このApplicationContextというのは、アプリケーション全体で使われる各種のコンテキスト(※1)を管理するクラスです。

ApplicationContextクラスはIoCコンテナ(※2)だといえます。このApplicationContextで各種のBeanが管理され、取得されたBeanによってアプリケーションの様々な情報が得られるようになっているのです。アプリケーションで利用するBeanは、すべてこのApplicationContextを使って取得します。

(※1) アプリケーションで使われる設定や各種の情報のこと。SpringにおいてはBeanのことを指す。

(※2)Inversion of Control(制御の反転)のこと。

通常のプログラムでは、私たちがコンポーネントを作成し、その中から必要なライブラリの機能などを呼び出していきます。が、DIの世界では、コンポーネントを呼び出すのはIoCコンテナの側です。(制御の反転)

この制御の反転を行うためのコンテナが「IoCコンテナ」です。

app = new ClassPathXmlApplicationContext("bean.xml");
  • ClassPathXmlApplicationContextはApplicationContextのサブクラス
  • bean.xmlを利用するApplicationContextインスタンスを生成
SampleBean bean = (SampleBean)app.getBean("sample");
  • Bean名(=beanタグ内のid)を指定する
SampleBean bean = app.getBean(SampleBean.class);
  • クラス名(=beanタグのclass)を指定する
  • キャストの必要がない

インターフェース化

  • Bean構成ファイルによって、messageの値が変更された場合もbean.xmlを修正するだけで済むようになった。(再コンパイルする必要も無くなった)
  • 取得したBeanのインスタンスをSampleBean以外のクラスに差し替えることができない

インターフェースの作成

  1. <SampleBean.java> - <Refactor> - <Extract Interface...>を選択

    スクリーンショット 2019-09-27 4.40.31.png

  2. インターフェース名と移行するメソッドを設定
    スクリーンショット 2019-09-27 4.42.37.png

作成/変更されたクラス

  • SampleBeanInterface.java
public interface SampleBeanInterface {

  public abstract Date getDate();

  public abstract String getMessage();

  public abstract void setMessage(String message);

}
  • SampleBean.java
public class SampleBean implements SampleBeanInterface {

(省略)

}
  • App.java
public class App {

  private static ApplicationContext app;

  public static void main(String[] args) {
    app = new ClassPathXmlApplicationContext("bean.xml");
    SampleBeanInterface bean = (SampleBeanInterface)app.getBean("sample");
    System.out.println(bean);
  }
}

別のBeanクラスの設定

  • SampleBean2.java
public class SampleBean2 implements SampleBeanInterface {

  private Date date;
  private String message;

  public SampleBean2() {
    this.date = new Date();
  }

  public SampleBean2(String message) {
    this();
    this.message = message;
  }

  public Date getDate() {
    return date;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  @Override
  public String toString() {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    return "message + "(" + format.format(date) + ")";
  }
} 
  • bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="sample" class="jp.spring.sample.SampleBean2">
    <property name="message" value="this is new bean!">
    </property>
  </bean>
</beans>
  • 実行結果
this is new bean!(2019-09-25)

Bean構成ファイル(XML)を用いない解決

  • XMLによる設定は面倒(という人もいる)
  • 設定ファイルを使わないフレームワークが増えている

Bean構成クラスの作成

  1. <File> - <New> - <Class>を選択
    スクリーンショット 2019-09-27 6.03.43.png

  2. クラス名を設定
    スクリーンショット 2019-09-27 6.04.50.png

クラスの編集

  • SampleBeanConfig.java
@Configuration
public class SampleBeanConfig {

  @Bean
  public SampleBeanInterface sampleBean(){
    return new SampleBean("This is Bean Config!");
  }
}
  • App.java
public class App {

  private static ApplicationContext app;

  public static void main(String[] args) {
    app = new AnnotationConfigApplicationContext("SampleBeanConfig.class");
    SampleBeanInterface bean = app.getBean(SampleBeanInterface.class);
    System.out.println(bean);
  }
}

AnnotationConfigApplicationContextとは

  • アノテーションによる設定情報を利用するためのApplicationContextのサブクラス

アノテーションについて

@Configuration

  • Beanの構成を定義したファイルであることを示す

@Bean

  • Bean構成クラスにおいて、Beanインスタンスを定義するためのメソッドであることを示す
  • Bean構成ファイル(=bean.xml)におけるbeanタグと同じ
7
4
1

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
7
4