Spring IoC就是控制反轉,也被稱爲依賴注入(Dependency Injection, DI),是面向對象編程中的一種設計理念,用來下降程序代碼之間的耦合度。正則表達式
依賴是什麼:算法
依賴就是在代碼中經過局部變量、方法參數、返回值等創建的對於其餘對象的調用關係。spring
1 /** 2 * @content 接口 3 * @author Gawain 4 * @date 2017-8-15下午8:02:37 5 */ 6 public interface DependDemo { 7 /** 8 * 顯示信息 9 */ 10 void showInfo(); 11 } 12 13 /** 14 * @content 實現類 15 * @author Gawain 16 * @date 2017-8-15下午8:02:30 17 */ 18 public class DependDemoImpl implements DependDemo { 19 /** 20 * 實現方法 21 */ 22 @Override 23 public void showInfo() { 24 System.out.println("你好"); 25 } 26 } 27 28 /** 29 * @content 測試類 30 * @author Gawain 31 * @date 2017-8-15下午8:02:09 32 */ 33 public class Demo { 34 public static void main(String[] args) { 35 //實例化依賴的對象,此時,Demo類依賴於DependDemoImpl類 36 DependDemo demo = new DependDemoImpl(); 37 //調用方法 38 demo.showInfo(); 39 } 40 }
經過上面的代碼能夠看出,Demo類和DependDemoImpl類高度耦合,若是需求變化須要替換DependDemo接口的實現類DependDemoImpl的話,那麼Demo中的代碼也須要進行改動。編程
解決方法(控制反轉):設計模式
建立一個對象工廠,將建立實例的工做交給工廠去作,得到對象時不經過new的方式而是經過工廠來得到對象。數據結構
1 /** 2 * @content 對象工廠 3 * @author Gawain 4 * @date 2017-8-15下午8:11:27 5 */ 6 public class Factory { 7 /** 8 * 返回對象實例 9 * @return 10 */ 11 public static DependDemo getDepend() { 12 return new DependDemoImpl(); 13 } 14 } 15 16 /** 17 * @content 測試類 18 * @author Gawain 19 * @date 2017-8-15下午8:02:09 20 */ 21 public class Demo { 22 public static void main(String[] args) { 23 //經過對象工廠得到實例 24 DependDemo demo = Factory.getDepend(); 25 //調用方法 26 demo.showInfo(); 27 } 28 }
經過上面的代碼能夠看出,Demo類再也不依靠自身的代碼去得到所依賴的具體的DependDemo對象,而是將這一工做交給了對象工廠去作,若是DependDemo接口的實現類須要替換的話,只要在工廠類修改代碼便可。此時由工廠來控制建立對象而不是Demo自己,這就是控制反轉。app
按照上面的方法雖然能夠解決問題,可是大量的工廠類會被引入到開發過程當中,大大的增長了開發的工做量。此時咱們就須要用到Spring了。框架
Spring爲咱們提供了完整的IoC實現,讓咱們得以專一於業務類和DAO類的設計。數據結構和算法
1.下載Spring的jar包並添加到項目中。也可使用MyEclipse來簡化這一步驟。右擊項目,選擇MyEclipse-->Add Spring Capabilities...而後直接點擊Finish。ide
2.編寫Spring配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 8 <!-- 經過bean元素聲明須要Spring建立的實例。該實例的類型經過class屬性指定,並經過id屬性爲該實例指定一個名稱,以便於訪問 --> 9 <bean id="dependDemo" class="com.jazz.demo.DependDemoImpl"/> 10 </beans>
補充:
1.applicationContext.xml是MyEclipse自動幫你添加的。若是你是本身導的jar包的話,這一文件需本身手動建立。
2.上述代碼中的id屬性也可使用name屬性來完成相同的工做。兩者的不一樣之處在於id屬性只能指定一個名稱,而name屬性能夠指定多個名稱,多個名稱之間使用空格或者逗號隔開。
3.class屬性是類的全限定類名。
3.編寫代碼經過Spring獲取DependDemo實例
1 import org.springframework.context.ApplicationContext; 2 import org.springframework.context.support.ClassPathXmlApplicationContext; 3 4 /** 5 * @content 測試類 6 * @author Gawain 7 * @date 2017-8-15下午8:02:09 8 */ 9 public class Demo { 10 public static void main(String[] args) { 11 //經過ClassPathXmlApplicationContext實例化Spring的上下文 12 ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml"); 13 //經過ApplicationContext的getBean()方法根據id來獲取bean的實例 14 DependDemo demo = con.getBean("dependDemo", DependDemoImpl.class); 15 //調用方法 16 demo.showInfo(); 17 } 18 }
補充:
1.在上面的代碼中,ApplicationContext是一個接口,負責讀取Spring配置文件,管理對象的加載、生成,維護Bean對象與Bean對象之間的依賴關係,負責Bean的生命週期等。
2.ClassPathXmlApplicationContext是ApplicationContext接口的實現類,用於從classpath路徑中讀取Spring配置文件。classpath路徑就是src文件夾。
3.寫在配置文件中的Bean會在ClassPathXmlApplicationContext加載Spring配置文件時建立生成。
Spring IoC它就是一個容器,負責管理Bean的建立以及管理Bean與Bean之間的關係等等。
依賴注入是什麼?
依賴注入就是將Bean的建立以及爲屬性賦值的工做交給Spring容器來作,從而避免組件之間以硬編碼的方式耦合在一塊兒。
上文提到過,Spring IoC不只能夠管理對象的加載與生成,還能夠管理Bean與Bean之間的依賴關係。除此以外,還能夠在建立Bean時爲Bean中的屬性賦初值。
下面再寫一個小例子演示一下依賴注入。
1 /** 2 * @content 書實體類 3 * @author Gawain 4 * @date 2017-8-15下午9:16:43 5 */ 6 public class Book { 7 //書籍名稱 8 private String bookName; 9 //重寫toString方法 10 @Override 11 public String toString() { 12 return "Book [bookName=" + bookName + "]"; 13 } 14 15 public String getBookName() { 16 return bookName; 17 } 18 19 public void setBookName(String bookName) { 20 this.bookName = bookName; 21 } 22 } 23 24 25 /** 26 * @content 用戶實體類 27 * @author Gawain 28 * @date 2017-8-15下午9:15:52 29 */ 30 public class User { 31 //姓名 32 private String name; 33 //年齡 34 private int age; 35 //正在讀的書籍 36 private Book book; 37 //重寫toString方法 38 @Override 39 public String toString() { 40 return "User [name=" + name + ", age=" + age + ", book=" + book + "]"; 41 } 42 public String getName() { 43 return name; 44 } 45 public void setName(String name) { 46 this.name = name; 47 } 48 public int getAge() { 49 return age; 50 } 51 public void setAge(int age) { 52 this.age = age; 53 } 54 public Book getBook() { 55 return book; 56 } 57 public void setBook(Book book) { 58 this.book = book; 59 } 60 }
1 /** 2 * @content 業務邏輯層接口 3 * @author Gawain 4 * @date 2017-8-15下午9:13:48 5 */ 6 public interface UserService { 7 /** 8 * 顯示信息 9 */ 10 void showInfo(); 11 } 12 13 14 /** 15 * @content 業務邏輯層實現類 16 * @author Gawain 17 * @date 2017-8-15下午9:39:25 18 */ 19 public class UserServiceImpl implements UserService { 20 private User user; 21 public User getUser() { 22 return user; 23 } 24 public void setUser(User user) { 25 this.user = user; 26 } 27 //顯示用戶信息 28 @Override 29 public void showInfo() { 30 System.out.println(user); 31 } 32 }
1 /** 2 * @content user控制層,此處做爲測試類 3 * @author Gawain 4 * @date 2017-8-15下午9:31:35 5 */ 6 public class UserController { 7 public static void main(String[] args) { 8 ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml"); 9 UserService userService = con.getBean("userService", UserServiceImpl.class); 10 userService.showInfo(); 11 } 12 }
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> 8 <!-- 經過bean元素聲明須要Spring建立的實例。該實例的類型經過class屬性指定,並經過id屬性爲該實例指定一個名稱,以便於訪問 --> 9 <bean id="dependDemo" class="com.jazz.demo.DependDemoImpl"/> 10 <!-- 聲明book對象 --> 11 <bean id="book" class="com.jazz.pojo.Book"> 12 <!-- 爲屬性賦值 --> 13 <property name="bookName" value="Java數據結構和算法" /> 14 </bean> 15 <!-- 聲明user對象 --> 16 <bean id="user" class="com.jazz.pojo.User"> 17 <property name="name" value="Gawain" /> 18 <property name="age" value="18" /> 19 <!-- 使用ref引用book對象,添加依賴關係 --> 20 <property name="book" ref="book" /> 21 </bean> 22 <!-- 聲明service對象 --> 23 <bean id="userService" class="com.jazz.services.impl.UserServiceImpl"> 24 <property name="user" ref="user"/> 25 </bean> 26 </beans>
補充:
1.爲屬性賦值的方式有不少種,除了上文的設值注入外,還有構造注入和p命名空間注入。
構造注入語法:
<constructor-arg index="" value="" />
其中value是值,index是指構造方法中的第幾個參數,從0開始。
p命名空間注入語法:
1 <beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns:p="http://www.springframework.org/schema/p" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <bean name="john-classic" class="com.example.Person"> 7 <property name="name" value="John Doe"/> 8 <property name="spouse" ref="jane"/> 9 </bean> 10 <bean name="john-modern" 11 class="com.example.Person" 12 p:name="John Doe" 13 p:spouse-ref="jane"/> 14 <bean name="jane" class="com.example.Person"> 15 <property name="name" value="Jane Doe"/> 16 </bean> 17 </beans>
使用p命名空間注入須要在beans中添加兩個url,基本類型的屬性使用p:屬性名=屬性值的方式注入,引用類型的屬性使用p:屬性名-ref=引用bean的id的方式注入。
2.除了基本數據類型和自定義數據類型以外,Spring還支持不少數據類型,以下圖所示。此處就不一一列舉了。你們能夠去Spring的幫助文檔中查看。
依賴注入其實就是將對象之間的依賴關係交給Spring來管理和組裝了。不要看它名字說的很「高大上」,其實實現起來很簡單。
Spring AOP簡介:
Spring AOP就是面向切面編程(Aspect Oriented Programming, AOP),是軟件編程思想發展到必定階段的產物,是面向對象編程(Object Oriented Programming, OOP)的有益補充。AOP通常適用於具備橫切邏輯的場合,例如訪問控制、事務管理、性能檢測等。
橫切邏輯是什麼:
你們先來看一段代碼
1 public class UserController { 2 //聲明日誌 3 static Logger log = Logger.getLogger(UserController.class); 4 public static void main(String[] args) { 5 //在方法執行前輸出日誌 6 log.info("顯示用戶信息"); 7 //使用try-catch來進行對異常的處理 8 try { 9 ApplicationContext con = new ClassPathXmlApplicationContext("applicationContext.xml"); 10 UserService userService = con.getBean("userService", UserServiceImpl.class); 11 userService.showInfo(); 12 } catch (Exception e) { 13 log.error("顯示用戶信息失敗", e); 14 } 15 } 16 }
上面的代碼是一段典型的日誌輸出+異常處理的代碼,從上面的代碼能夠看出,代碼中添加了大量的日誌和異常處理的代碼,而咱們實際的業務代碼只有3行。
日誌、異常處理、事務控制是一個健壯的業務系統所必須的,可是爲了保證系統健壯可用,就須要在衆多的業務方法中「反覆」編寫相似的代碼,使得本來就很複雜的業務處理代碼變得更加複雜。
在業務系統中,總有一些散落、滲透到系統各處且不得不處理的事情,這些穿插在既定業務中的操做就是所謂的「橫切邏輯」,也被稱爲「切面」。
面向切面編程極大的簡化了上面代碼中「重複」但又不得不寫的代碼,可使咱們在不改變原程序的基礎上爲代碼段增長新的功能,對代碼段進行加強處理。它的設計思想來源於代理設計模式。
Spring AOP基本概念:
1.切面(Aspect):一個模塊化的橫切邏輯(或橫切關注點),可能會橫切多個對象。
2.鏈接點(Join Point):程序執行中的某個具體的執行點。
3.加強處理(Advice):切面在某個特定鏈接點上執行的代碼邏輯。
4.切入點(Pointcut):對鏈接點的特徵進行描述,可使用正則表達式。加強處理和一個切入點表達式關聯,並在與這個切入點匹配的某個鏈接點上運行。
5.目標對象(Target object):被一個或多個切面加強的對象。
6.AOP代理(AOP proxy):由AOP框架所建立的對象,實現執行加強處理方法等功能。
7.織入(Weaving):將加強處理鏈接到應用程序中的類型或對象上的過程。
8.加強處理類型:有前置加強、後置加強、環繞加強、異常拋出加強、最終加強等等。這些加強處理實現方式都差很少。
除了上文說的技術以外,spring的幫助文檔也給咱們提供了至關全面且詳細的說明。