根據(jù)時間安排迷郑,今天主要是對spring中IOC的理解躯砰。對于IOC的理解可以從以下幾個角度去分析每币。
- 什么是IOC?如何使用案例來理解琢歇?
- IOC有哪幾種實(shí)現(xiàn)方式兰怠?
- IOC的底層實(shí)現(xiàn)過程是什么?
根據(jù)這幾個角度李茫,開始今天的故事揭保,
1 什么是IOC?
對于IOC的理解魄宏,主要是停留在概念和幾種注入的方式上秸侣,雖然知道其生命周期,但是對整個bean管理的宏觀角度娜庇,理解的不夠深刻塔次。
IOC:控制反轉(zhuǎn)(Inversion of Control)容器,是一種設(shè)計(jì)思想名秀。意味著將你設(shè)計(jì)好的對象交給容器控制励负。
1.1 什么是依賴注入
這個概念的理解,我準(zhǔn)備使用一個案例來表示匕得。如果a類中包含了b類继榆,就說明a類對b類產(chǎn)生了依賴。如一個人需要車汁掠,這就說人對車產(chǎn)生了依賴略吨。
class User{
Car car;
public User(){
car=new Car();
}
}
上面這個案例,可以看到考阱,在User類中翠忠,包含了Car類,也就說User類對Car類產(chǎn)生了依賴乞榨。
按照傳統(tǒng)的方式秽之,User類如果想要使用Car基本上就是在內(nèi)部new一個新對象即可。但是這樣做缺點(diǎn)很大吃既,new的方式也就意味著User和Car產(chǎn)生了緊耦合考榨。不利于大規(guī)模使用。于是使用了另外一種方式可以代替鹦倚。那就是什么時候用到Car河质,從外部直接傳遞過來就好。這樣的話,耦合性就大大降低了掀鹅。再看下面這種形式是不是就好很多了散休。
class User{
Car car;
public User(Car car){
this.car=car;
}
}
像這樣的方式就是依賴注入,也就是把依賴Car注入到了User中淫半。
1.2 什么是控制反轉(zhuǎn)
有了上面依賴注入的概念溃槐,再立即控制反轉(zhuǎn)就比較簡單了。
誰控制誰:傳統(tǒng)方式User是在內(nèi)部new科吭,現(xiàn)在我們通過依賴注入的方式注入依賴對象Car』璧危現(xiàn)在spring出現(xiàn)了,發(fā)明了IOC对人,IOC里面有一個容器谣殊,這些依賴對象全部交給容器去管理。也就是說這些依賴對象的控制權(quán)交給了容器牺弄。
如何反轉(zhuǎn):傳統(tǒng)方式User是主動去new姻几,這種方式是正轉(zhuǎn)。反轉(zhuǎn)是由容器來幫忙創(chuàng)建及注入依賴對象势告;
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是對于外部bean對象引用萍恕,與被引用的bean對象的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;
}
}
這種方式簡單易操作。
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)過程
以上的幾種注入方式维哈,可能有個疑問,那就是bean是如何從xml登澜,再到注入類中的呢?看下面這張圖
Spring IOC容器初始化的核心過程主要有四個步驟(還有一些如:后置加載器飘庄,國際化脑蠕,事件廣播器等一些過程不展開):
- Bean定義的定位,Bean 可能定義在XML中,或者一個注解谴仙,或者其他形式迂求。這些都被用Resource來定位,讀取Resource獲取BeanDefinition 注冊到 Bean定義注冊表中晃跺。
- 第一次向容器getBean操作會觸發(fā)Bean的創(chuàng)建過程,實(shí)列化一個Bean時 ,根據(jù)BeanDefinition中類信息等實(shí)列化Bean揩局。
- 將實(shí)列化的Bean放到單列Bean緩存內(nèi)。
- 此后再次獲取向容器getBean就會從緩存中獲取掀虎。
這張圖是核心的過程凌盯。這個過程是已經(jīng)簡化了,具體的實(shí)現(xiàn)方式要設(shè)計(jì)到bean的生命周期的管理烹玉。安排到下一章節(jié)了驰怎。
spring的核心內(nèi)容就是aop和ioc,知道了這倆是如何實(shí)現(xiàn)的之后二打,就是核心bean管理的核心實(shí)現(xiàn)县忌,最后對配置文件進(jìn)行介紹。