淺談Spring注入模型
Spring注入bean的方式
DI exists in two major variants: Constructor-based dependency injection and Setter-based dependency injection.
從Spring的官網(wǎng)中可以得知,Spring注入bean的方式由兩種,一種是通過構(gòu)造方法進行注入,另外一種是通過setter方法進行注入。
但熟悉Spring開發(fā)的同學在實際的開發(fā)中經(jīng)常使用的注入方式是通過@Autowired以及@Resource的方式來注入bean的。那么通過注解的方式注入是跟上面兩種注入方式是一樣的嗎?在研究這個問題之前,我們需要來了解Spring的注入模型。
Spring的注入模型
如果不深入到Spring的源碼,是很少有機會了解到Spring的注入模型(AutowireMode)。但是為了掃清我們學習Spring源碼的障礙,我們有必要了解下Spring的注入模型。
Spring的注入模型有四種,分別是:
- autowire_no(0):默認的注入模型,如果在beanA中注入beanB,如果沒有提供注解或者xml的注入方式,beanB是無法注入到beanA中的。
- autowire_name(1):通過set方法注入,并且set的參數(shù)名必須和注入的bean名稱一樣,在xml中是通過byName
- autowire_type(2):通過set方法注入,set的參數(shù)名可以隨意命名,但是類型必須和注入的bean的類型一樣,在xml中是通過byType的方式配置
- autowire_constructor(3):通過構(gòu)造器注入
代碼示例
多說無益,我們直接上代碼來加深對這一概念的了解。
定義bean對象
我們簡單定義兩個類,分別是Student和Address,并且將他們注入到Spring容器中。
Student.java如下
@Component @Slf4j public class Student { private Address address; public Student(){ log.info("default constructor..."); } public Student(Address address){ log.info("constructor inject...{}", address); this.address = address; } public void setAddress(Address address){ log.info("setter...{}", address); this.address = address; } public void showAddress(){ this.address.info(); } }
Address.java如下
@Component public class Address { public void info(){ System.out.println("廣東省廣州市白云區(qū)"); } }
我們可以看到在Student中有一個屬性是Address,并且提供了默認的構(gòu)造方法以及帶參數(shù)的構(gòu)造方法,同時還有一個 set方法。
定義配置類
我們再定義一個config類,用來掃描這兩個類所在的包路徑,把這兩個類注入到Spring容器中。
@ComponentScan("org.example.autoModel.model") public class MyBeanConfig { }
定義后置處理器
在Spring中,我們可以在自己定義的后置處理器BeanFactoryPostProcessor,獲取到對應(yīng)的BeanDefinition。
相信大家在學習Spring的時候有了解過BeanDefinition,不熟悉的可以搜索下BeanDefinition的概念,如果閱讀過Spring的源碼的話,對BeanDefinition應(yīng)該就更加熟悉了。這里就不做過多的解釋了,后面在解讀Spring源碼的時候應(yīng)該也會涉及到這部分的知識。
簡單的來說,就是一個對象被注入到Spring中,實際是被解析成BeanDefinition對象,里面保存了各種需要用到的信息,并且可以在后置處理器中獲取到對應(yīng)的BeanDefinition對象,然后對其做一些操作。
@Slf4j(topic = "e") public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition("student"); // beanDefinition.setAutowireMode(3); log.debug("mode:{}",beanDefinition.getAutowireMode()); } }
上面代碼所示,我們可以獲取這個beanDefinition在Spring容器中對應(yīng)的autowireMode的值,并且可以修改這個autowireMode的值,來觀察下注入模型的改變,對bean的注入方式有什么影響。
定義測試方法
@Test public void modelTest(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(MyBeanConfig.class); context.register(MyBeanFactoryPostProcessor.class); context.refresh(); Student student = context.getBean(Student.class); student.showAddress(); }
執(zhí)行測試方法,得出如下的結(jié)果。
如上面所示,我們可以得到對應(yīng)的autowireMode的值是0,并且是執(zhí)行了Student的默認構(gòu)造方法,由于沒有將address屬性注入到student中,所在調(diào)用address對應(yīng)的方法的時候,拋出了空指針的異常。
針對上面的對象,我們可以簡單分析下:
- Spring默認的注入模型是0
- 注入模型是0,意味著執(zhí)行默認的構(gòu)造方法,并且不會執(zhí)行set方法去進行注入address這個對象,所以拋出了空指針異常
我們可以在后置處理器中,修改對應(yīng)autowioreMode的值,將autowireMode的值修改成1。
beanDefinition.setAutowireMode(1);
然后執(zhí)行該測試方法,得到下面的結(jié)果。
可以看到我們將注入模型的值修改成1,之后,spring就會通過set方法,將address注入到student中,就可以成功調(diào)用address的方法了。
當然,我們將注入模型的值修改成2,也是注入成功的,并且也是通過set方法,只不過是byType和byName的區(qū)別。這個同學們可以自己嘗試下。
下面,我們將注入模型的值修改成3來看下執(zhí)行的結(jié)果。
beanDefinition.setAutowireMode(3);
結(jié)果如下:
可以看到,如果將注入模型的值修改成了3,那么Spring是通過帶參的構(gòu)造方法來注入給student的。
通過上面簡單的例子,我們就可以了解到注入模型autowireMode對注入方式的影響,這為我們以后閱讀Spring的源碼打下了基礎(chǔ)。
自動注入和手動注入
上面我們將autowireMode值修改成1、2、3,就可以完成屬性的自動注入。那如果我們不去修改autowireMode的值,而是使用注解來將屬性注入到student中,會是怎樣的結(jié)果呢?
我們來看下面的代碼:
@Component @Slf4j public class Student { @Autowired private Address address; public Student(){ log.info("default constructor..."); } public Student(Address address){ log.info("constructor inject...{}", address); this.address = address; } public void setAddress(Address address){ log.info("setter...{}", address); this.address = address; } public void showAddress(){ this.address.info(); } }
@Slf4j(topic = "e") public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition("student"); // beanDefinition.setAutowireMode(3); log.debug("mode:{}",beanDefinition.getAutowireMode()); } }
查看結(jié)果
我們發(fā)現(xiàn)使用@Autowired注解注入屬性的時候,注入模型的值是0,也就是默認的值。
對于@Autowired的注解,我的看法是,使用注解注入屬性是手動注入的方式,Spring提供自動注入的方式只有set方法以及帶參的構(gòu)造方法。而注解的注入方式,只不過是xml手動注入的一種簡化,Spring內(nèi)部處理的機制都是類似的。
了解過xml配置的同學大概有些印象,我們需要指定bean中屬性所對應(yīng)的類的全路徑。而使用自動注入,我們可以指定byType或者byName。由于xml方式太久沒用了,大概就是這么個意思吧。
所以我認為@Autowired注入的方式,不是自動注入,而是手動注入,只不過Spring容器內(nèi)部幫我們處理了。當然,關(guān)于Spring容器如何處理@Autowired注解的方式注入屬性的,同學們可以通過閱讀源碼來大致了解下。后面大概也會解讀下這部分的源碼。
以上便是鄙人對Spring注入模型的淺薄認識,如果有錯誤的話,還請同學們多多包涵。
到此這篇關(guān)于淺談Spring注入模型的文章就介紹到這了,更多相關(guān)Spring注入模型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java?中?Class?Path?和?Package的使用詳解
這篇文章主要介紹了Java?中?Class?Path和Package的使用詳解,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下2022-08-08java開發(fā)ServiceLoader實現(xiàn)機制及SPI應(yīng)用
這篇文章主要為大家介紹了java開發(fā)ServiceLoader實現(xiàn)機制及SPI應(yīng)用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10Java類如何實現(xiàn)一個類的障眼法(JadClipse的bug)
這篇文章主要介紹了Java類實現(xiàn)一個類的障眼法(JadClipse的bug),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12Java對象初始化過程代碼塊和構(gòu)造器的調(diào)用順序
這篇文章主要介紹了Java對象初始化過程代碼塊和構(gòu)造器的調(diào)用順序,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08關(guān)于mybatis-plus-generator的簡單使用示例詳解
在springboot項目中集成mybatis-plus是很方便開發(fā)的,最近看了一下plus的文檔,簡單用一下它的代碼生成器,接下來通過實例代碼講解關(guān)于mybatis-plus-generator的簡單使用,感興趣的朋友跟隨小編一起看看吧2024-03-03Java數(shù)字格式類(NumberFormat類和DecimalFormat類)用法詳解
NumberFormat類是Java提供的一個格式化數(shù)字的類,可以將一串數(shù)字轉(zhuǎn)化成自己想要的數(shù)據(jù)格式,也可以將字符串轉(zhuǎn)化成數(shù)值,下面這篇文章主要給大家介紹了關(guān)于Java數(shù)字格式類(NumberFormat類和DecimalFormat類)用法的相關(guān)資料,需要的朋友可以參考下2022-07-07java實現(xiàn)數(shù)據(jù)結(jié)構(gòu)單鏈表示例(java單鏈表)
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)實現(xiàn)單鏈表示例,需要的朋友可以參考下2014-03-03