Spring系列之IOC的理解和分析
根據(jù)時(shí)間安排,今天主要是對(duì)spring中IOC的理解。對(duì)于IOC的理解可以從以下幾個(gè)角度去分析。
什么是IOC?如何使用案例來理解?
- IOC有哪幾種實(shí)現(xiàn)方式?
- IOC的底層實(shí)現(xiàn)過程是什么?
- 根據(jù)這幾個(gè)角度,開始今天的故事,
1 什么是IOC?
對(duì)于IOC的理解,主要是停留在概念和幾種注入的方式上,雖然知道其生命周期,但是對(duì)整個(gè)bean管理的宏觀角度,理解的不夠深刻。
IOC:**控制反轉(zhuǎn)(Inversion of Control)容器,**是一種設(shè)計(jì)思想。意味著將你設(shè)計(jì)好的對(duì)象交給容器控制。
1.1 什么是依賴注入
這個(gè)概念的理解,我準(zhǔn)備使用一個(gè)案例來表示。如果a類中包含了b類,就說明a類對(duì)b類產(chǎn)生了依賴。如一個(gè)人需要車,這就說人對(duì)車產(chǎn)生了依賴。
- class User{
- Car car;
- public User(){
- car=new Car();
- }
- }
上面這個(gè)案例,可以看到,在User類中,包含了Car類,也就說User類對(duì)Car類產(chǎn)生了依賴。
按照傳統(tǒng)的方式,User類如果想要使用Car基本上就是在內(nèi)部new一個(gè)新對(duì)象即可。但是這樣做缺點(diǎn)很大,new的方式也就意味著User和Car產(chǎn)生了緊耦合。不利于大規(guī)模使用。于是使用了另外一種方式可以代替。那就是什么時(shí)候用到Car,從外部直接傳遞過來就好。這樣的話,耦合性就大大降低了。再看下面這種形式是不是就好很多了。
- class User{
- Car car;
- public User(Car car){
- this.car=car;
- }
- }
像這樣的方式就是依賴注入,也就是把依賴Car注入到了User中。
1.2 什么是控制反轉(zhuǎn)
有了上面依賴注入的概念,再立即控制反轉(zhuǎn)就比較簡(jiǎn)單了。
- 誰控制誰:傳統(tǒng)方式User是在內(nèi)部new,現(xiàn)在我們通過依賴注入的方式注入依賴對(duì)象Car?,F(xiàn)在spring出現(xiàn)了,發(fā)明了IOC,IOC里面有一個(gè)容器,這些依賴對(duì)象全部交給容器去管理。也就是說這些依賴對(duì)象的控制權(quán)交給了容器。
- 如何反轉(zhuǎn):傳統(tǒng)方式User是主動(dòng)去new,這種方式是正轉(zhuǎn)。反轉(zhuǎn)是由容器來幫忙創(chuàng)建及注入依賴對(duì)象;
2 依賴注入的幾種形式
目前主要有五種注入方式:SET注入,構(gòu)造器注入,靜態(tài)工廠,實(shí)例工廠。
本文直接使用網(wǎng)上的基本案例來實(shí)現(xiàn)。比如UserService依賴UserDao。先把UserDao定義好了,接下來看如何實(shí)現(xiàn)注入的。
- public class UserDao {
- public String userLogin() {
- return "userLogin()方法";
- }
- }
下面看幾種依賴注入的幾種實(shí)現(xiàn)方式。
2.1 set注入
第一步: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="userDao" class="com.xxx.demo.UserDao"></bean>
- <!-- setter注入 -->
- <bean id="userService" class="com.xxx.demo.UserService">
- <!--ref是對(duì)于外部bean對(duì)象引用,與被引用的bean對(duì)象的id保持一致-->
- <property name="userDao" ref="userDao"></property>
- </bean>
- </beans>
第二步:set方式注入
- public class UserService {
- //一定要提供屬性的setter方法
- private UserDao userDao;
- public void userlogin() {
- String res=userDao.userLogin();
- System.out.println(res);
- }
- public void setUserDao(UserDao userDao) {
- this.userDao = userDao;
- }
- }
這種方式簡(jiǎn)單易操作。
2.2 構(gòu)造器注入
第一步: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="userDao" class="com.xxx.demo.UserDao"></bean>
- <!-- 構(gòu)造器注入 -->
- <bean id="userServiceV2" class="com.xxx.demo.UserServiceV2">
- <constructor-arg index="0" ref="userDao"></constructor-arg>
- <constructor-arg index="1" value="印度三哥"></constructor-arg>
- </bean>
- </beans>
第二步:構(gòu)造器注入
- public class UserServiceV2 {
- private UserDao userDao;
- private String name;
- public void userlogin() {
- String res=userDao.userLogin();
- System.out.println(res);
- System.out.println(name);
- }
- public UserServiceV2(UserDao userDao,String name) {
- super();
- this.userDao = userDao;
- this.name = name;
- }
- }
2.3 靜態(tài)工廠注入
第一步: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">
- <!-- 靜態(tài)工廠注入 -->
- <bean id="userDao01" class="com.xxx.demo.StaticFactory" factory-method="createuserDao"></bean>
- <bean id="userService01" class="com.xxx.demo.UserService">
- <property name="userDao" ref="userDao01"></property>
- </bean>
- </beans>
第二步:定義靜態(tài)工廠
- public class StaticFactory {
- public static UserDao createuserDao(){
- return new UserDao();
- }
- }
第三部:靜態(tài)工廠注入
- public class UserService {
- private UserDao userDao;
- public void userlogin() {
- String res=userDao.userLogin();
- System.out.println(res);
- }
- public void setUserDao(UserDao userDao) {
- this.userDao = userDao;
- }
- }
2.4 實(shí)例化工廠
第一步: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">
- <!-- 實(shí)例化工廠 -->
- <bean id="instanceFactory" class="com.xxx.demo.InstanceFactory"></bean>
- <bean id="userDao3" factory-bean="instanceFactory" factory-method="createUserDao"></bean>
- <bean id="userService02" class="com.xxx.demo.UserService">
- <property name="userDao" ref="userDao3"></property>
- </bean>
- </beans>
第二步:工廠注入
- public class InstanceFactory {
- public UserDao createUserDao(){
- return new UserDao();
- }
- }
以上就是幾種常見的注入方式。在開發(fā)中比較常用。知道了IOC的概念和幾種實(shí)現(xiàn)方式之后,下面主要探討IOC的底層實(shí)現(xiàn)原理。
3 IOC底層實(shí)現(xiàn)過程
以上的幾種注入方式,可能有個(gè)疑問,那就是bean是如何從xml,再到注入類中的呢?看下面這張圖
Spring IOC容器初始化的核心過程主要有四個(gè)步驟(還有一些如:后置加載器,國際化,事件廣播器等一些過程不展開):
- Bean定義的定位,Bean 可能定義在XML中,或者一個(gè)注解,或者其他形式。這些都被用Resource來定位,讀取Resource獲取BeanDefinition 注冊(cè)到 Bean定義注冊(cè)表中。
- 第一次向容器getBean操作會(huì)觸發(fā)Bean的創(chuàng)建過程,實(shí)列化一個(gè)Bean時(shí) ,根據(jù)BeanDefinition中類信息等實(shí)列化Bean。
- 將實(shí)列化的Bean放到單列Bean緩存內(nèi)。
- 此后再次獲取向容器getBean就會(huì)從緩存中獲取。
這張圖是核心的過程。這個(gè)過程是已經(jīng)簡(jiǎn)化了,具體的實(shí)現(xiàn)方式要設(shè)計(jì)到bean的生命周期的管理。安排到下一章節(jié)了。spring的核心內(nèi)容就是aop和ioc,知道了這倆是如何實(shí)現(xiàn)的之后,就是核心bean管理的核心實(shí)現(xiàn),最后對(duì)配置文件進(jìn)行介紹。
本文轉(zhuǎn)載自微信公眾號(hào)「愚公要移山」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系愚公要移山公眾號(hào)。