一、耦合
1、什么是耦合?
通過代碼來理解
1 package com.justnow.demo01.service; 2 3 import com.justnow.demo01.dao.UserDao; 4 5 public class UserService { 6 private UserDao userDao = new UserDao(); 7 8 public void updateById(int id){ 9 userDao.updateById(id); 10 } 11 }
UserService類能夠編譯運行成功的前提是UserDao這個類不出問題,也就是說,UserService依賴UserDao這個類。這種依賴性的高低可以用耦合來表示。
在軟件工程中, 耦合指的就是就是對象之間的依賴性。對象之間的耦合越高,維護成本越高。因此對象的設計應使類和構件之間的耦合最小。
總結:
耦合是影響軟件復雜程度和設計質量的一個重要因素,在設計上我們應采用以下原則:如果模塊間必須存在耦合,就盡量使用數據耦合,少用控制耦合,限制公共耦合的范圍,盡量避免使用內容耦合。
2、解決程序耦合的思路
(1) 反射
如,可以使用以下方法注冊jdbc驅動,
1 Class.forName("com.mysql.jdbc.Driver");
好處就是,我們的類中不再依賴具體的驅動類。
(2) 工廠模式解耦
創建一個工廠類UserDaoFactory,使用反射技術,實例化UserDao
1 package com.justnow.demo01.factory; 2 3 import static java.lang.Class.forName; 4 public class DaoFactory { 5 public static Object getUserDao(){ 6 Object obj = null; 7 try { 8 obj = Class.forName("com.justnow.demo01.dao.UserDao").newInstance(); 9 } catch (InstantiationException e) { 10 e.printStackTrace(); 11 } catch (IllegalAccessException e) { 12 e.printStackTrace(); 13 } catch (ClassNotFoundException e) { 14 e.printStackTrace(); 15 } 16 return obj; 17 } 18 }
然后修改UserService中的代碼:
1 package com.justnow.demo01.service; 2 3 import com.justnow.demo01.dao.UserDao; 4 import com.justnow.demo01.factory.DaoFactory; 5 6 public class UserService { 7 private UserDao userDao = (UserDao) DaoFactory.getUserDao();// 使用反射的方法進行 8 9 10 public void updateById(int id){ 11 userDao.updateById(id); 12 } 13 }
也就是,這樣便可以達到解耦的作用!
(3) 控制反轉
控制反轉(Inversion of Control,縮寫為IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。——百度百科
① 傳統的Java SE程序設計過程中,如果一個類依賴與另一個類的話,需要通new 進行創建對象,這個過程是程序主動去創建依賴對象;而IoC是通過一個容器創建這些對象,即有Ioc容器來控制對象的創建。即IoC容器控制了對象
② 正常的方法是主動控制獲取依賴對象,這個正傳;而反轉是由容器來創建以及注入依賴對象,這個就是反轉!
上述過程可以,用下圖來表示
傳統程序設計過程:
使用IoC容器后,在客戶端類中不再主動去創建這些對象了。如下圖所示
談談對Spring IOC的理解 - TD李的文章 - 知乎 https://zhuanlan.zhihu.com/p/47649591
③ 依賴注入Dependency Injection(DI)
依賴注入:組件之間依賴關系由容器在運行期決定,形象的說,即由容器動態的將某個依賴關系注入到組件中。依賴注入的目的並非為軟件系統帶來更多功能,而是為了提升組件重用的頻率,並為系統搭建了一個靈活、可擴展的平台。
通過依賴注入方法,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。
- 應用程序依賴於IoC容器
- 應用程序需要IoC容器來提供對象需要的外部資源
- IoC容器注入應用程序依賴的對象
- 外部資源包括:對象、資源和常用數據
二、Spring中的控制反轉(IoC)
1、Spring中的容器
在基於Spring的應用中,應用對像生存於Spring容器中。Spring容器創建對象,裝配它們,配置它們。管理它們的生命周期,從生存到死亡(或者創建到銷毀)。Spring容器使用依賴注入管理構成應用的組件,她會創建相互協作的組件之間的關聯。
也就是說,Spring容器在其框架中充當了控制反轉的調控系統。
Spring中的容器可以歸納為兩種不同的類型,一個是Bean工廠,另一個是引用上下文(application)。其中,應用上下文的使用更加廣泛。
2、Spring中的bean
簡而言之,Spring bean是Spring框架在運行時管理的對象。Spring bean是任何Spring應用程序的基本構建。Spring bean的管理包括:
(1) 創建一個對象
(2) 提供依賴項(例如其他bean,配置屬性)
(3) 攔截對象的方法調用以提供額外的框架功能
(4) 銷毀一個對象
Spring bean詳細介紹 - Java架構的文章 - 知乎 https://zhuanlan.zhihu.com/p/60256169
三、在Spring中使用IoC初體驗
第一步:在pom.xml中添加坐標
- spring-core
- spring-beans
- spring-expression
- spring-context
具體如下:
1 <properties> 2 <spring.version>5.0.2.RELEASE</spring.version> 3 </properties> 4 5 <!-- 依賴 --> 6 <dependencies> 7 <!--spring--> 8 <dependency> 9 <groupId>org.springframework</groupId> 10 <artifactId>spring-context</artifactId> 11 <version>${spring.version}</version> 12 </dependency> 13 14 <dependency> 15 <groupId>org.springframework</groupId> 16 <artifactId>spring-beans</artifactId> 17 <version>${spring.version}</version> 18 </dependency> 19 20 <dependency> 21 <groupId>org.springframework</groupId> 22 <artifactId>spring-core</artifactId> 23 <version>${spring.version}</version> 24 </dependency> 25 26 <dependency> 27 <groupId>org.springframework</groupId> 28 <artifactId>spring-expression</artifactId> 29 <version>${spring.version}</version> 30 </dependency> 31 <dependency> 32 <groupId>junit</groupId> 33 <artifactId>junit</artifactId> 34 <version>4.12</version> 35 <scope>test</scope> 36 </dependency> 37 </dependencies>
第二步:創建IUserDao接口和它的實現類
IUserDao接口
1 package com.justnow.dao; 2 3 public interface IUserDao { 4 public void updateById(int id); 5 }
UserDaoImpl 實現類
1 package com.justnow.service.impl; 2 3 import com.justnow.dao.IUserDao; 4 import com.justnow.service.IUserService; 5 6 public class UserServiceImpl implements IUserService { 7 8 private IUserDao userDao; 9 10 public IUserDao getUserDao() { 11 return userDao; 12 } 13 14 public void setUserDao(IUserDao userDao) { 15 this.userDao = userDao; 16 } 17 18 @Override 19 public void updateById(int id) { 20 userDao.updateById(10); 21 } 22 }
其中,在實現類中添加了userDao這個屬性的get和set方法。
第三步:編寫spring框架的配置文件,applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <!--配置 service --> 7 <bean id="userService" class="com.justnow.service.impl.UserServiceImpl"> 8 <property name="userDao" ref="userDao" /> 9 </bean> 10 <!--配置 dao --> 11 <bean id="userDao" class="com.justnow.dao.impl.UserDaoImpl" /> 12 13 </beans>
<bean id="userService" class="com.justnow.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao" />
</bean>
意思是:這個bean的id為"userService",對應的類是com.justnow.service.impl.UserServiceImpl,有一個屬性的名字為userDao。ref="userDao",表示這個屬性引用的bean的id為userDao。
第四步:編寫測試類
1 package com.justnow.test; 2 3 import com.justnow.dao.IUserDao; 4 import com.justnow.service.IUserService; 5 import org.junit.Test; 6 import org.springframework.context.support.ClassPathXmlApplicationContext; 7 8 public class TestDemo1 { 9 10 @Test 11 public void testBean(){ 12 //1. 使用ApplicationContext接口,就是在獲取spring容器 13 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); 14 //2. 根據Bean的id值,從容器總獲取對象 15 IUserService userService = (IUserService) context.getBean("userService"); 16 //3. 調用userService這個對像中的updateById的方法 17 userService.updateById(10); 18 } 19 20 }
最終的結果:
本章代碼:https://github.com/justn0w/javawebdemo/tree/master/spring/Spring_Demo1
總結:
使用Spring的IoC容器,可以避免傳統方法對象和對象之間關系復雜,達到的解耦的作用,接下來,還會介紹一些更加神奇的方法,咱們拭目以待!
參考:
Spring bean詳細介紹 - Java架構的文章 - 知乎 https://zhuanlan.zhihu.com/p/60256169
談談對Spring IOC的理解 - TD李的文章 - 知乎 https://zhuanlan.zhihu.com/p/47649591