Spring實戰拆書--SpringBean

1.準備工做java

請在github上下載源碼結合文章閱讀,效果更佳git

在建立了SpringBoot項目後,咱們首先須要開啓組件掃描,以下代碼所示。github

 
@Configuration //掃描指定包目錄 @ComponentScan(basePackages="com.wjc") public class BeanConfig { }

聲明一個測試Bean的接口,全文的主要內容都是經過此接口的實現類完成的spring

若是想學習Java工程化、高性能及分佈式、深刻淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友能夠加個人Java高級交流:854630135,羣裏有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給你們。數據庫

 
package com.wjc.spring.bean; public interface Bird { void fly(); void feed(); void twitter(); void changeTwiter(); }

2.自動裝配express

自動裝配是最多見的Bean裝配形式。session

咱們首先寫一個Bird接口的實現類來展現自動裝配,只需一個「@Component」註解便可完成。多線程

 
package com.wjc.spring.bean.impl; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.wjc.spring.bean.Bird; //這是知更鳥 @Component public class Robin implements Bird { private String flyStr ="知更鳥起飛"; private String feedStr = "不想吃東西"; private String twiterStr = "啊啊啊"; @Override public void fly() { System.out.println(flyStr); } @Override public void feed() { System.out.println(feedStr); } @Override public void twitter() { System.out.println(twiterStr); } @Override public void changeTwiter() { } }

在測試時,咱們只須要使用「@Autowired」註解,就能夠拿到對應的對象了架構

經過Junit能夠測試裝配是否完成併發

若是想學習Java工程化、高性能及分佈式、深刻淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友能夠加個人Java高級交流:854630135,羣裏有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給你們。

 
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=BeanConfig.class) public class BeanTest { @Autowired private Bird bird; //測試1,查看是否自動裝配了知更鳥 //此時bean.impl只有robin @Test public void BeanTest1() { assertNotNull(bird); } }

3.處理自動裝配的歧義性(@Qualifier)

試想若是我有2個Bird接口的實現類,spring在裝配時是否會由於不知道具體須要哪一個實現類而報錯?

此時聲明一個「Parrot」,也實現bird接口,運行test方法會如何?

 
package com.wjc.spring.bean.impl; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.wjc.spring.bean.Bird; //這是鸚鵡 @Component public class Parrot implements Bird { private String flyStr ="鸚鵡起飛"; private String feedStr = "啥都吃"; private String twiterStr = "說人話"; @Override public void fly() { System.out.println(flyStr); } @Override public void feed() { System.out.println(feedStr); } @Override public void twitter() { System.out.println(twiterStr); } @Override public void changeTwiter() { twiterStr = "你好你好"; } }

運行結果以下:

 

 
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.wjc.spring.test.BeanTest': Unsatisfied dependency expressed through field 'bird'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.wjc.spring.bean.Bird' available: expected single matching bean but found 5: parrot,quail,robin,Cuckoo1,Cuckoo2 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)

能夠看到,因爲Spring並不知道應該將哪個實現類注入到bird中,報出了 「UnsatisfiedDependencyException」,咱們能夠經過註解「@Qualifier("parrot")」來解決此問題

 
//這是鸚鵡 @Component @Qualifier("parrot") public class Parrot implements Bird {

在獲取實現類時使用以下方式,便可獲取到本身想要的對象實例了

 
@Autowired @Qualifier("parrot") private Bird parrot; //添加@Qualifier("parrot")來解決聲明問題 @Test public void BeanTest3() { // 此時鸚鵡添加了@Primary parrot.fly(); assertNotNull(parrot); }

4.Bean的做用域

已知Spring默認是單例模式,但在多線程高併發的狀況下,單例模式其實未必是最佳選擇,若是線程A將Bean賦了值,而此時線程B拿取了被A賦值的對象,並返回了對應的結果,此時是否是會出現B返回了預料以外的結果?

本文簡單討論一下原型模式下Bean的傳遞,和會發生的問題,具體的各自做用域請百度「spring做用域」

已知Spring做用域以下:singleton / prototype / request / session /global session

咱們來看一下以下代碼,一個原型模式的對象

 
package com.wjc.spring.bean.impl; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import com.wjc.spring.bean.Bird; //這是鵪鶉 //這個使用原型模式 @Component @Qualifier("Quail") @Scope("prototype") public class Quail implements Bird { private String flyStr ="鵪鶉起飛"; private String feedStr = "鵪鶉想吃啥就吃啥"; private String twiterStr = "鵪鶉不知道怎麼叫"; @Override public void fly() { // TODO Auto-generated method stub System.out.println(flyStr); } @Override public void feed() { // TODO Auto-generated method stub System.out.println(feedStr); } @Override public void twitter() { // TODO Auto-generated method stub System.out.println(twiterStr); } public void changeTwiter() { twiterStr = "我大鵪鶉今天就是餓死。。。。"; } }

看下在TEST時他的表現如何:

 
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=BeanConfig.class) public class BeanTest3 { @Autowired @Qualifier("Quail") private Bird bird; @Autowired @Qualifier("Quail") private Bird bird2; //測試原型模式與單例的區別 @Test public void BeanTest1() { bird.twitter(); bird.changeTwiter(); bird.twitter(); bird2.twitter(); bird2.changeTwiter(); bird2.twitter(); } }

運行結果:

 
鵪鶉不知道怎麼叫 我大鵪鶉今天就是餓死。。。。 鵪鶉不知道怎麼叫 我大鵪鶉今天就是餓死。。。。

spring確實將此Bean對象變成了原型模式。那麼做用域是否就這麼簡單的完成了?

咱們看一下以下代碼

 
@Service public class BirdServiceImpl implements BirdService { @Autowired @Qualifier("Quail") private Bird bird; public void ScopTest() { bird.twitter(); bird.changeTwiter(); bird.twitter(); } }

運行測試類:

 
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=BeanConfig.class) public class ServiceTest { @Autowired private BirdService birdService; @Autowired private BirdService birdService2; //測試在Service上添加和不添加@Qualifier("Quail")時調用的Bean的區別 @Test public void ServiceTest2() { birdService.ScopTest(); birdService2.ScopTest(); } }

運行結果:

 
鵪鶉不知道怎麼叫 我大鵪鶉今天就是餓死。。。。 我大鵪鶉今天就是餓死。。。。 我大鵪鶉今天就是餓死。。。。

????????原型模式失效了????

爲何會發生這種狀況?由於在此場景下,「BirdServiceImpl」是單例模式的,對Bean的操做不可避免的變成了單例的,若是添加以下代碼結果就會徹底不同

 
@Service @Scope("prototype") public class BirdServiceImpl implements BirdService { @Autowired @Qualifier("Quail") private Bird bird; public void ScopTest() { bird.twitter(); bird.changeTwiter(); bird.twitter(); } }

再次運行時:

 
鵪鶉不知道怎麼叫 我大鵪鶉今天就是餓死。。。。 鵪鶉不知道怎麼叫 我大鵪鶉今天就是餓死。。。。

假設「ServiceTest」方法爲Control層,「BirdServiceImpl」方法爲Service層,「Quail」爲Bean,在實際應用時,應該考慮Scop註解是否會能夠成功生效。

以下爲測試後的結果

 
//當Service上有@Scope("prototype"),Bean上有@Scope("prototype")時 返回不一樣對象 //當Service上有@Scope("prototype"),Bean上無@Scope("prototype")時 返回相同對象 //當Service上無@Scope("prototype"),Bean上有@Scope("prototype")時 返回相同對象 //當Service上無@Scope("prototype"),Bean上無@Scope("prototype")時 返回相同對象

5.注入式聲明Bean

在上述代碼中,我都是經過硬編碼的形式在輸入一些內容的,那麼可否經過讀取配置文件的方式完成輸出內容呢?(實際運用場景:獲取數據庫鏈接對象Session)

咱們首先定義一個對象,能夠看到我沒有添加任何註解,由於此對象不須要在這裏進行裝配!

 
package com.wjc.spring.bean.impl; import com.wjc.spring.bean.Bird; //這是杜鵑 public class Cuckoo implements Bird { private String flyStr = "fly" ; private String feedStr = "feed"; private String twiterStr = "twiter"; public Cuckoo(String flyStr, String feedStr, String twiterStr) { super(); this.flyStr = flyStr; this.feedStr = feedStr; this.twiterStr = twiterStr; } @Override public void fly() { // TODO Auto-generated method stub System.out.println(flyStr); } @Override public void feed() { // TODO Auto-generated method stub System.out.println(feedStr); } @Override public void twitter() { // TODO Auto-generated method stub System.out.println(twiterStr); } @Override public void changeTwiter() { // TODO Auto-generated method stub twiterStr = "杜鵑"; } }

若是想學習Java工程化、高性能及分佈式、深刻淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友能夠加個人Java高級交流:854630135,羣裏有阿里大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給你們。

咱們將Config改造一下,由他來負責裝配對象

 
package com.wjc.spring.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import com.wjc.spring.bean.impl.Cuckoo; @Configuration //掃描指定包目錄 @ComponentScan(basePackages="com.wjc") @PropertySource("classpath:Cuckoo.properties") public class BeanConfig { //開啓組件掃描 //獲取資源 @Autowired private Environment env; //經過配置文件裝配Cuckoo @Bean(name="Cuckoo1") public Cuckoo getbird() { return new Cuckoo(env.getProperty("flyStr","fly"), env.getProperty("feedStr","feed"), env.getProperty("twiterStr","twiter")); //return new Cuckoo("fly","feed", "twiter"); } @Bean(name="Cuckoo2") public Cuckoo getbird2() { return new Cuckoo("fly","feed", "twiter"); } }

能夠看到我聲明瞭2個"Cuckoo"對象實例,分別叫「Cuckoo1」,「Cuckoo2」

使用Test方法來執行一下

 
package com.wjc.spring.test; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.wjc.spring.bean.impl.Cuckoo; import com.wjc.spring.config.BeanConfig; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=BeanConfig.class) public class BeanTest4 { @Autowired @Qualifier("Cuckoo2") private Cuckoo Cuckoo; @Autowired @Qualifier("Cuckoo1") private Cuckoo Cuckoo1; //測試經過配置文件裝配Bean @Test public void BeanTest1() { Cuckoo1.fly(); Cuckoo1.feed(); Cuckoo1.twitter(); Cuckoo.fly(); Cuckoo.feed(); Cuckoo.twitter(); } }

執行結果

cuckoo fly cuckoo feed cuckoo twiter fly feed twiter

能夠看到成功的聲明瞭對象。

歡迎工做一到八年的Java工程師朋友們加入Java高級交流:854630135

本羣提供免費的學習指導 架構資料 以及免費的解答

不懂得問題均可以在本羣提出來 以後還會有直播平臺和講師直接交流噢

相關文章
相關標籤/搜索