[SpringBoot] Beanとは一体何者なのか?

2016.08.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Springフレームワークに馴染んだ後、SpringBootに触れた方はこのような疑問は持たれないのでしょうが、 僕のようにSpringを知らずにSpringBootを始める方も中にはいるのではないかと思い、僕が非常に悩んだBeanというものについて僕が現状知っていることを書いてみようと思います。

注) 間違っていること、説明が不足していることありましたらご指摘いただければ嬉しいです。

結論

間違いを恐れずに言えばBeanとは

@Beanと書いたメソッドでインスタンス化されたクラスがシングルトンクラスとしてDIコンテナに登録される。任意のクラスで@Autowiredで注入してアクセスできる。

と僕は理解しました。
わかりにくいですね。
僕も文章だけではうまく説明できないので、結論に至るまでの過程を書いていきます。

調査

まず@Beanというものについて調べた時に @Configurationと記述したクラス内のメソッドに@Beanを記述することで@Beanを定義することができ、任意のクラスで@Autowiredで注入することで定義したBeanを使うことができる。

ということで僕が最初に書いたコードがこんな感じです。

※@Scheduledは定期実行するためのアノテーションになります。興味のある方はこちらをどうぞ!

CreateBean.java

@Configuration
public class CreateBean {

	@Bean
	public String getHoge(){
		return "hoge";
	}
}

BatchProcessing.java

@Component
public class BatchProcessing {
	
	@Autowired
	CreateBean createBean;
	
	@Scheduled(initialDelay = 3000, fixedDelay = 5000)
	public void initialDelay(){
		System.out.println(createBean.getHoge());
	}
}

結果は

hoge
hoge
hoge
hoge

試しに@Beanを消してビルドしてもエラーも出ず、同じ結果になります。

じゃあ結局Beanって何なんだ!!
アノテーションなくても動くじゃん!!

バカですいません。

@Beanの正しい使い方は以下のようになります。

Count.java

public class Count {

	private int count;
	
	public int getCount(){
		return count++;
	}
}

このクラスは、呼ばれるたびに変数countをインクリメントして返すgetCount()メソッドと、インクリメントする変数countだけを持ったシンプルなクラスです。

CreateBean.java

@Configuration
public class CreateBean {

	@Bean
	public Count getCount(){
		return new Count();
	}
}

ここでCountクラスをDIコンテナに登録しています。

BatchProcessing.java

@Component
public class BatchProcessing {

	@Autowired
	Count count;

	@Scheduled(initialDelay = 3000, fixedDelay = 5000)
	public void initialDelay(){
		System.out.println(count.getCount());
	}
}

ここで登録したCountクラスを@Autowiredで注入しています。

0
1
2
3

メソッドに@Beanを記述するという言葉に引っ張られて、普通のStringやintを返すメソッドに@Beanを記述していましたが Stringやintを返すメソッドに@Beanをつけても何の意味もありません。

@Beanを記述したメソッドでインスタンス化したクラスを返して、DIコンテナに登録します。そして任意のクラスで@Autowiredで変数に注入して使うようです。

わかってしまえば簡単なことなのになぜ僕はあんな無駄な時間を。。

さらに

BatchProcessing.java

@Component
public class BatchProcessing {

	@Autowired
	OuterBatchProcessing outerBatchProcessing;
	@Autowired
	Count count;

	@Scheduled(initialDelay = 3000, fixedDelay = 5000)
	public void initialDelay(){
		System.out.println(count.getCount() + " : from BatchProcessing");
	}
	@Scheduled(initialDelay = 5000, fixedDelay = 5000)
	public void OuterProcessing(){
		outerBatchProcessing.execute();
	}
}

BatchProcessingクラスを少し直して

OuterBatchProcessing.java

@Component
public class OuterBatchProcessing {

	@Autowired
	private Count count;
	
	public void execute(){
		System.out.println(count.getCount() + " : from OuterBatchProcessing");
	}
}

別のクラスからも登録しているBeanを使ってみます。

結果は

0 : from BatchProcessing
1 : from OuterBatchProcessing
2 : from BatchProcessing
3 : from OuterBatchProcessing
4 : from BatchProcessing
5 : from OuterBatchProcessing

@Beanで定義したクラスはデフォルトではシングルトンとしてDIコンテナに格納されるようですね。

最後に

Srpingに馴染んでいる方にとっては当たり前のことなんだろうなと思いながら、SpringBootから始めた僕のような迷い子がいるのではないかと思い書いてみました。 SpringBoot + Gradle の組み合わせで始めるとネットの情報は Spring + Maven の情報が多くわかりにくいので、今後もSpringBoot + Gradle の組み合わせで開発した時のことを書いていこうと思います。

参考

http://www.riem.nagoya-u.ac.jp/~ohta/etc/springboot-5.html