1. 程式人生 > >Spring學習5(1):IoC容器之IoC概述,JAVA反射機制,資源訪問器

Spring學習5(1):IoC容器之IoC概述,JAVA反射機制,資源訪問器

spring學習5(1)

 在經過了對spring框架基本開發的瞭解以及對spring boot流程的學習,《精通spring4.x…》這本書正式開始了spring的講解,我也跟隨著這本書的腳步進行學習。

IoC概述

 首先需要學習的是spring的IoC技術,IoC全稱是Inverse of Control,是spring容器的核心。

IoC的基本意義

 即是將一個介面具體實現類的控制權從呼叫的類中移除,交給第三方來控制。如果從電影劇本的角度即是說,演員,劇本,角色的對應由導演來控制。在spring中就是spring容器借用Bean配置來進行控制。  後來由於這個概念不夠直觀引入了DI(Dependency Injection)依賴注入的概念,即是說呼叫類對某一介面實現類的依賴關係由第三方注入。

IoC的型別

 IoC可以劃分為三種類型:建構函式注入,屬性注入,介面注入。Spring支援建構函式注入和屬性注入。

建構函式注入

 通過呼叫類的建構函式,將介面類通過建構函式給出。  用電影的例子就是,導演分配角色的演員,而後在劇本的建構函式中將這個演員注入。

屬性注入

 通過呼叫類的函式,將介面類通過函式給出。  用電影的例子就是不是這個角色在所有的場景都需要,所以這時候可以通過setter方法來注入演員。

介面注入

 將呼叫類所有依賴注入的方法抽取到一個介面中,呼叫類通過實現該介面的注入方法來達成注入。

通過容器完成依賴關係的注入

 雖然如同上述一般操作後,呼叫類之間完成了解耦,然而這些程式碼在第三個類中依然存在。就好像導演要控制其他兩個類,如果這時候有個第三方的代理機構只是讓導演,劇本,演員各司其職,那麼三個類都完成了解耦。那麼spring就是這樣一個容器,通過new XmlBeanFactory)

就可以啟動容器並且完成裝配。

JAVA反射機制

 java語序通過程式化的方式間接對Class進行操作。

概念

 可以通過一例子來說明。通常我們要實現一個類並賦予初值可以使用建構函式直接賦值,或是建立後用setter方法來賦值,這就屬於直接呼叫目標類。  於此相對,我們可以建立一個ClassLoader用來獲取當前執行緒,而後通過指定的全限定類名來裝載目標類的反射例項。之後我們就可以利用反射類的各個物件來操作類,從而達到建立等方法的實現的目標。

類裝載器ClassLoader

定義和工作流程

 類裝載器就是尋找類的節碼檔案並構造出類在jvm內部表示物件的元件。其經歷以下步驟把一個類裝入jvm:

  1. 裝載:查詢和匯入Class檔案
  2. 連結:
    1. 校驗:檢查載入Class檔案資料的正確性
    2. 準備:給類的靜態變數分配儲存空間
    3. 解析:將符號引用轉換成直接引用
  3. 初始化:對類的靜態變數,靜態程式碼塊執行初始化工作。

構成

 JVM在執行時會有三個ClassLoader,其中他們有父子關係:

  1. 根裝載器:使用c++編寫,在java中不可見,不是ClassLoader的子類,負責裝載jre的核心庫類。
  2. ExtClassLoader:是根裝載器的子類,負責裝載jre擴充套件目錄ext中的jar類包。
  3. AppClassLoader:是ExtClassLoader的子類,負責裝載classpath路徑下的類包,預設使用該類裝載應用程式的類。

全盤負責委託機制

 JVM有全盤負責委託機制,是指當一個ClassLoader載入一個類時,其所依賴和引用的類也由同一個ClassLoader載入;先委託父裝載器尋找目標類,只有找不到才從自己的路徑中查詢並轉載目標類。  這個機制也是導致NoSUchMethodError問題的原因,如果在類路徑有多個不同版本的類包就有可能導致錯誤。

反射機制

 即是可以從Class物件中獲取建構函式,成員變數方法類等反射物件即是包括了private或protected成員變數和方法的但是要申明setAccessible(boolean access)。  主要有:

  1. 類的建構函式反射類(Constructor):通過getConstructors(parameterType)方法(或getDeclaredConstructors(parameterType))獲取擁有特定入參的建構函式反射物件,並且可以通過newInstance來例項化。
  2. 類方法的反射類:通過getMethods()來獲得特定的方法反射類,其最主要的方法是invoke(Object obj, Object[] args)來呼叫原方法。
  3. 類的成員變數反射類:通過getDeclaredFields(String name)方法來獲取特定的成員變數反射類,可以通過set(Object obj, Object value)來使用。

 例項如下:

package com.smart.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;

public class ReflectTest{
	
	public static Car initByDefaultConst() throws Throwable{
	ClassLoader loader = Thread.currentThread().getContextClassLoader();
	Class clazz = loader.loadClass("com.smart.reflect.Car");
	
	Constructor cons = clazz.getDeclaredConstructor((Class[])null);
	Car car = (Car)cons.newInstance();
	
	Method setBrand = clazz.getMethod("setBrand", String.class);
	setBrand.invoke(car, "XXX");
	Method setColor = clazz.getDeclaredMethod("setColor", String.class);
	setColor.invoke(car, "Dark");
	Method setMaxSpeed = clazz.getDeclaredMethod("setMaxSpeed", int.class);
	setMaxSpeed.invoke(car, 200);
	return car;
}
	public static void main(String[] args) throws Throwable{
		Car car = initByDefaultConst();
		car.introduce();
	}
}

資源訪問利器

資源抽象介面

 jdk所提供的訪問資源的類並不能很好地滿足各種底層資源的訪問需求,比如從類路徑或web容器的上下文中獲取資源的能力。  為此,Spring設計了一個Resource介面,它為應用提供了更強的底層資源訪問能力。其主要方法如下: bollean exists():資源是否存在 bollean isOpen():資源是否開啟 URL getURL() throws IOException:如果底層資源可以表示程URL,則該方法返回對應的URL物件。 FIle getFile() throws IOException:如果底層資源對應一個檔案則該方法返回對應的File物件。 InputStream getInputStream() throws IOException:返回資源對應的輸入流。

具體實現類

  1. WriteableResource:可寫資源介面,有兩個實現類:FileSystemResource和PathResource。
  2. ByteArrayResource:二進位制陣列表示的資源。
  3. ClassPathResource:類路徑下的資源,資源以相對於類路徑的方式表示。
  4. FileSystemResource:檔案系統資源,資源用系統路徑的方式表示如“D:/XXX/XXX.xml”等。
  5. InputStreamResource:以輸入流返回表示的資源。
  6. ServletContextResource:為訪問Web容器上下文的資源而設計的類,負責以相對於web應用根目錄的路徑載入資源,支援以流和URL的方式訪問,在war解包的情況下,也可以通過File方式訪問。
  7. URLResource:URL封裝了java.net.URL可以訪問任何通過URL表示的資源。
  8. PathResource:提供的讀取資原始檔的類,可以訪問通過URL,Path,系統檔案路徑表示的資源。

 在獲取資源後,使用者就可以通過Reaource介面定義的多個方法來訪問檔案其他資訊,如getFileName()方法來獲取檔名,通過getInputStream()方法來獲取檔案的輸入流等。  注意在資源配置檔案在專案釋出時會被打包,所以不能使用getFile()方法了,而要用getInputSteam(),這個問題碼一下。

資源載入

資源地址表示式

 為了訪問不同型別的資源,必須使用相應的Resource實現類,spring提供了強大的載入資源機制來簡化了這一過程。僅通過資源地址的特殊標識就可以訪問相應的資源,還支援ant風格的資源地址。  有如下較常見的地址字首:

  1. classpath:/classpath:/:這兩個都是相對於類的根路徑開始。資原始檔可以在檔案系統中也可以在jar或zip的類包中。特別注意classpath*:可以掃描所有的同名包並載入所需。
  2. file::使用URLResource從檔案系統目錄中裝載資源,可以是相對路徑,也可以是絕對路徑。
  3. http://:使用UrlResource從web伺服器中裝載資源。
  4. ftp://:使用UrlResource從ftp伺服器中裝載資源
  5. 無字首:根據ApplicationContext來具體決定。

ant

 ant是一個允許萬用字元的格式

  1. ?:匹配檔名中的一個字元
  2. *:匹配檔名中的任意字元
  3. **:匹配多層路徑
  4. 。。。

資源載入器

spring定義了一套資源載入的介面其關係如下:

PathMatchingResourcePatternResolver->
ResourcePatternResolver->
ResourceLoader->
Resource

 這其中REsourceLoader介面是不支援ant的,但是ResourcePatternResolver擴充套件了其介面,而PathMathingResourcePatternResolver是spring的標準實現類,例子如下

package com.smart.resource;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.testng.annotations.*;
import static org.testng.Assert.*;

public class PatternResolverTest{
	@Test
	public void getResources() throws Throwable{
		ResourcePatternResolver resolver = 
				new PathMatchingResourcePatternResolver();
		
	
	
	Resource resources[] = resolver.getResources("classpath*:com/smart/**/*.xml");
	assertNotNull(resources);
	for(Resource resource:resources) {
		System.out.println(resource.getDescription());
	}
}
}