Spring超詳細講解IOC與解耦合
前言
回想寫過的圖書管理系統、租房系統、電影院賣票系統都是基於原生的JavaSE、OOP,沒有用到任何框架,在層與層的關系中一個類要想獲得與其他類的聯系主要的方式還是靠new,這就導致層與層之間、對象與對象之間的依賴性強“動一發而遷全身”。特別是在處理數據層和業務層之間時,由於對象沒有統一管理導致很復雜!而Spring中的IOC就很好地解決瞭這一問題,降低耦合就是它的一大特色
一.所謂耦合
個人建議:學習Spring之前要多寫原生的OOP項目,充分體會層之間、類之間的聯系才能深刻理解Spring的特色
在項目開發中,對象之間的耦合度就是多個對象間的依賴性、關聯性。對象之間的耦合越高,維護成本越高,因此對象的設計應使類和類之間的耦合最小
當使用Spring框架後你不用再考慮new對象瞭,隻要寫好配置文件,IOC就會幫你做,這就降低瞭層與層、對象與對象之間之間的耦合度
二.Spring
Spring是分層的Java SE/EE應用輕量級開源框架,以loC(Inverse Of Control:反轉控制)和AOP (Aspect Oriented Programming:面向切面編程)為內核
方便解耦,簡化開發 | 通過Spring提供的 loC容器,可以將對象間的依賴關系交由Spring進行控制,避免硬編碼所造成的過度耦合。用戶也不必再為單例模式類、屬性文件解析等這些很底層的需求編寫代碼,可以更專註於上層的應用 |
---|---|
AOP編程的支持 | 通過Spring的AOP功能,方便進行面向切面編程,許多不容易用傳統OOP實現的功能可以通過AOP輕松實現 |
聲明式事務的支持 | 可以將我們從單調煩悶的事務管理代碼中解脫出來,通過聲明式方式靈活的進行事務管理,提高開發效率和質量 |
方便程序的測試 | 可以用非容器依賴的編程方式進行幾乎所有的測試工作,測試不再是昂貴的操作,而是隨手可做的事情 |
降低JavaEE API的使用難度 | Spring對JavaEEAPl(如JDBC、JavaMail、遠程調用等)進行瞭薄薄的封裝層,使這些API的使用難度大為降低 |
三.核心IOC理解
IoC(Inversion of Control)名為控制反轉,顧名思義就是將控制權反轉
通過控制反轉,把對象的創建由原來的人為new反轉成Spring來處理,但是代碼中不可能出現沒有依賴的情況,所以IOC解耦隻是降低他們的依賴關系,不會消除依賴關系
1.容器
容器的核心是Bean,這個單詞譯為——豆莢,顧名思義我們的對象都被裝在這個豆莢裡統一管理
裡面存的是各種對象(在xml裡配置的bean、@repository. @service、@controller. @component) ,實際上就是抽象的(k-v)map——(id-class)
在項目啟動的時候會讀取配置文件裡面的bean節點,根據全限定類名使用反射創建對象放到map裡、掃描到打上上述註解的類還是通過反射創建對象放到map裡。這個時候map裡就有各種對象瞭,接下來我們在代碼裡需要用到裡面的對象時,再通過DI註入(autowired.resource等註解, xml裡bean節點內的ref屬性,項目啟動的時候會讀取xm|節點ref屬性根據id註入,也會掃描這 些註解,根據類型或id註入: id就是對象名)
2.控制反轉
沒有引入IOC容器之前
對象A依賴於對象B,那麼對象A在初始化或者運行到某一點的時候, 自己必須主動去創建對象B或者使用已經創建的對象B,無論是創建還是使用對象B,控制權都在自己手上
引入IOC容器之後
對象A與對象B之間失去瞭直接聯系,當對象A運行到需要對象B的時候,IOC容器會主動創建一個對象B註入到對象A需要的地方
通過前後的對比,不難看出來:對象A獲得依賴對象B的過程,由主動行為變為瞭被動行為,控制權顛倒過來瞭,這就是"控制反轉"這個名稱的由來
全部對象的控制權全部上繳給"第三方"IOC容器,所以,IOC容器成瞭整個系統的關鍵核心,它起到瞭一種類似“粘合劑,固體膠”的作用,把系統中的所有對象粘合在一起發揮作用, 如果沒有這個"粘合劑",對象與對象之間會彼此失去聯系,這就是有人把IOC容器比喻成“粘合劑”的由來
3.依賴註入
“獲得依賴對象的過程被反轉瞭"。控制被反轉之後,獲得依賴對象的過程由自身管理變為瞭由IOC容器主動註入。依賴註入是實現IOC的方法,就是由IOC容器在運行期間,動態地將某種依賴關系註入到對象之中(下面詳說)
四.Bean的實例化
以Dao層代表持久層,Service層代表業務層來舉例
1.無參構造
在Bean中存在默認無參構造函數的情況下,根據默認無參構造方法來創建對象,就像這樣:
<bean id="userDao" class="yu7daily.dao.impl.UserDaoImpl"/>
2.工廠靜態方法
①首先寫好配置文件
<bean id="userDao" class="yu7daily.factory.StaticFactory" factory-method="getUserDao"></bean>
②工廠的靜態方法返回Bean的實例
public class StaticFactory { public static UserDao getUserDao(){ return new UserDaoImpl(); } }
3.工廠實例方法(常用)
配置好工廠的Bean
<bean id="factory" class="yu7daily.factory.DynamicFactory"> <bean id="userDao" factory-bean="factory" factory-method="getUserDao"/>
返回實例化的Bean對象
public class DynamicFactory { public UserDao getUserDao(){ return new UserDaoImpl(); } }
由於上述的方式,factory-bean的名稱不固定,不夠簡便,於是又產生瞭新的簡便方法
public class UserDaoFactoryBean implements FactoryBean<UserDao> { //代替原始實例工廠中創建對象的方法 public UserDao getObject() throws Exception { return new UserDaoImpl(); } public Class<?> getObjectType() { return UserDao.class; } }
我還可以通過public boolean isSingleton() { return true; }
來確定造出的對象是否為單例(true代表單例)
配置bean也變得簡單很多
<bean id="userDao" class="yu7daily.factory.UserDaoFactoryBean"/>
五.Bean的依賴註入
他是Spring核心IOC的具體體現,簡言之就是把持久層對象傳入業務層,不用我們自己去new瞭依賴註入的目的就是降低耦合
依賴註入的前提是寫好Bean配置,和上面的相似,以下就不寫瞭
1.set註入
set註入可以減少硬編碼問題,本質是在容器內部將一個類設置到另一個類中,就像這樣
而在這裡,想要在容器內部實現把B設置到A中就可以通過set註入的方式,實現起來就是在A類中寫一個引入B的set方法,就像這樣:
xmlns:p="http://www.springframework.org/schema/p"<bean id="a" class="yu7daily.service.A" p:b-ref="b">
private B b; public void setB(B b) { this.b = b; }
這樣的話我們就可以在A中為所欲為地調用B裡的方法啦關鍵是不用new~
比較起來看,不用註入依賴的話,我想在A類中調用B裡的方法還需要獲取容器、得到Bean、最後得來對象,十分麻煩
2.有參構造
和Set註入大同小異,本質也是類之間的設置,隻不過是形式不同而已
private B b; public A(B b) { this.b = b; }
六.第一個Spring案例
①導入開發的基本坐標
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.22.RELEASE</version> </dependency> </dependencies>
②編寫接口和實現類
③創建Spring核心配置文件
在類路徑中的resources裡創建
<?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"> </beans>
④在Spring配置文件中向bean裡添加BookDaoImql和BookServiceImpl
<!-- 配置bean--> <!-- id表示給bean起名字,class表示給bean定義類型--> <bean id="bookDao1" class="yu7daily.dao.impl.BookDaoImpl"/> <bean id="bookService" class="yu7daily.service.impl.BookServiceImpl"> <!--配置service與dao的關系,也就是數據層和業務層--> <!-- property標簽表示配置當前bean的屬性--> <!-- name屬性表示配置哪一個具體的屬性--> <!-- ref屬性表示參照哪一個bean--> <property name="bookDao" ref="bookDao1"/> </bean>
⑤使用Spring的API獲取Bean的實例
//獲取ioc容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //獲取bean BookDao bookDao = (BookDao) ctx.getBean("bookDao1"); bookDao.save(); //獲取service BookService bookService = (BookService) ctx.getBean("bookService"); bookService.save();
運行結果:
到此這篇關於Spring超詳細講解IOC與解耦合的文章就介紹到這瞭,更多相關Spring IOC與解耦合內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java Spring框架簡介與Spring IOC詳解
- Java 自定義Spring框架以及Spring框架的基本使用
- Spring實例化bean的四種方式詳解
- Spring操作JdbcTemplate數據庫的方法學習
- 詳解Spring Bean的配置方式與實例化