- 依存性と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の目的
###「依存している状態」とは
- 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内から切り離す
- SampleBeanのインスタンスを生成する処理
- messageに値を設定する処理
##Bean構成ファイル(XML)による解決
- XMLの情報を元にインスタンスを自動生成し、プログラム内で利用できるようにする
###ファイルの作成
###ファイルの編集
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以外のクラスに差し替えることができない
###インターフェースの作成
###作成/変更されたクラス
- 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構成クラスの作成
###クラスの編集
- 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のサブクラス
###アノテーションについて
- Beanの構成を定義したファイルであることを示す
- Bean構成クラスにおいて、Beanインスタンスを定義するためのメソッドであることを示す
- Bean構成ファイル(=bean.xml)におけるbeanタグと同じ