#IOC容器java
#類裝載器ClassLoadergit
尋找類的字節碼文件並構造出類再JVM內部標識對象的組件。再Java中, 類裝載器吧一個類裝入JVM,須要入如步驟: (1)裝載:查找和導入Class文件. (2)連接:執行校驗,準備和解析步驟,其中解析步驟是能夠選擇的。 1.準備:給類的靜態遍歷分配存儲空間。 2.校驗: 檢查載入Class文件數據的正確性。 3.解析:將符好引用轉換成直接引用。 (3)初始化:對類的靜態變量,靜態代碼塊執行初始化工做.
#JVM裝載類時使用的機制github
JVM裝載類時使用"全盤負責委託機制","全盤負責"是指當一個ClassLoader裝載一個類時 ,除非顯示的使用另外一個ClassLoader,該類所依賴的類也由這個ClassLoader載入;"委託機制" 是指原先委託父裝載器尋找目標類,只有找不到的狀況下才從本身的類路徑中查找而且裝載目標類 ,這也是出於安全考慮。
#Java的反射機制web
Class反射對象描述類雨衣結構,能夠從class對象重獲取構造函數,成員變量,方法類等類元素的反射對象,並以編程的方式經過這些反射對象對目標類對象進行操做。這些反射對象類在java.reflect包中定義。 - Constructor:類的構造函數反射類,經過Class#getConstructors()方法能夠獲取類的全部構造函數反射對象數組,在Java5.0中,還能夠經過getConstructor(Class...parameterTypes)獲取特定入參的構造函數反射對象。Constructor的一個主要方法事newInstance(Object[] initargs),經過改方法能夠建立一個對象的實例,至關於使用new關鍵字。在Java5.0中,改方法演化爲更爲靈活的形式:newInstance(Onject) - Method:類方法的反射類,經過Class#getDeclaredMethods()方法能夠獲取類的全部方法反射類對象數組Method[].在Java5.0中,能夠經過getDeclaredMethod(String name,Class...parameterTypes)獲取特定簽名的方法 name是方法名,Class...爲方法入參類型列表。Method最主要的方法是invoke(Object obj,Object[] args),其中obj標識操做的目標對象;args爲方法入參。Method的其餘方法以下 getTypeParameters getReturnType getGenericReturnType getParameterTypes getExceptionTypes - Field:類的成員變量的反射類,經過Class#getDeclaredFields()方法能夠獲取類的程願變量反射對象數組,經過Class#getDeclaredField(String name)則能夠獲取某個特定名稱的成員變量反射對象。Field類最主要的方法是set(Object obj,Object value),其中object標識操做的目標對象,經過value爲目標對象的成員變量設置值,若是爲基礎類型可使用Field類中提供的待類型名的值設置方法。
實例: github:https://github.com/chenanddom/SpringSection4/blob/master/src/main/java/com/flexible/ioc/reflect/ReflectDemo.javaspring
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //類裝載器獲取Car類對象 ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class clazz = loader.loadClass("com.flexible.ioc.reflect.Person"); //獲取類的默認構造器對象而且經過它實例化 // Constructor constructor = clazz.getDeclaredConstructor((Class[]) null); Constructor constructor = clazz.getDeclaredConstructor((Class[]) null); Person person = (Person) constructor.newInstance(); //經過反射方法設置屬性 Method setUserName = clazz.getMethod("setUserName", String.class); setUserName.invoke(person, "zhangsan"); Method setUserAge = clazz.getMethod("setUserAge", Integer.class); setUserAge.invoke(person, 26); System.out.println(person.toString()); // System.out.println(setUserAge.getReturnType());//獲取返回值類型 // System.out.println(setUserAge.getParameterTypes());//獲取參數類型 System.out.println(setUserAge.getParameterAnnotations()); System.out.println(loader); System.out.println(loader.getParent()); //根記載器不是ClassLoader的子類,是C++寫的,沒法獲取到 System.out.println(loader.getParent().getParent()); } }
#資源訪問編程
JDK缺乏從類路徑或者Web容器上下文中獲取資源的操做類。Spring針對此限制設計了一個Resource接口,它爲應用提供了更強的底層資源訪問能力。該接口用於對應的不一樣的資源類型的實現類。Resource接口的主要方法以下: //資源是否存在 boolean exists(); //資源是否可讀 boolean isReadable(); //資源是否被打開 boolean isOpen(); //若是底層資源能夠標識成URL,則該方法返回對應的URL對象 URL getURL() throws IOException; //獲取圖片的uri URI getURI() throws IOException; //底層資源對應一個文件,則該方法返回對應的File對象 File getFile() throws IOException; // long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String var1) throws IOException; String getFilename(); String getDescription(); //由於集成了InputStreamSource,因此也有獲取流的方法 InputStream getInputStream() throws IOException;
Resource在Spring起到了不可獲取的做用,Spring框架使用Resource裝載各類資源,包括配置文件資源,國際化屬性文件資源等。它的具體實現類圖以下: 數組
- WritableResource:可寫資源接口,Spring3.1新家的接口,實現累如圖所示,FileSystemResource和PathResource(Spring4.0加的) - ByteArrayResource->AbstractResource:繼承了AbstractResource,標識二進制數組的資源,二進制數組的資源能夠在內存中經過程序構造。 - ClassPathResource:類路徑下的資源,資源以相對路徑的方式標識,若是代碼所示:
public class FileSourceDemo { public static void main(String[] args) { String filePath = "E:\\BaiduNetdiskDownload\\wangpan\\SpringSection4\\src\\main\\resources\\conf\\file1.txt"; try { //使用系統文件路徑方式加載文件 WritableResource res1 = new PathResource(filePath); //使用類路徑方式加載文件 Resource res2 = new ClassPathResource("conf/file1.txt"); //使用WritableResource接口寫資源文件 OutputStream stream1 = res1.getOutputStream(); stream1.write("這是使用spring Resource接口的例子".getBytes()); stream1.close(); //使用Resource接口讀資源文件 InputStream ins1 = res1.getInputStream(); InputStream ins2 = res2.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int i; while ((i=ins1.read())!=-1){ baos.write(i); } System.out.println(baos.toString()); System.out.println("res1:"+res1.getFilename()); System.out.println("res2:"+res2.getFilename()); } catch (IOException e) { e.printStackTrace(); } } }
-FileSystemResource:文件系統資源,資源以文件系統路徑的方式所示,如D:/conf/bean.xml. - InpustreamResource:以輸入流返回標識的資源。 - ServletContextResource:爲訪問Web容器上下文中的資源而設置的類,負責以相對於web應用根目錄的路徑加載資源,它支持以流和URL的方式訪問,在WAR解包的狀況下,也能夠經過File方式訪問。該類還能夠直接從jar包中訪問資源。 - UrlResource:URL封裝了java.net.URL,它使用戶可以訪問任何能夠通URL標識的資源,如文件系統的資源,HTTP資源,FTP資源等。 -PathResource:Spring4.0提供的讀取資源文件的新類,Path封裝了java.net.URL,java.nio.file.Path(Java7提供),文件系統資源,它使用戶呢剛剛訪問任何能夠經過URL,Path,系統文件路徑標識的資源,文件系統,HTTP,FTP資源。
##資源加載 爲了訪問不類型的資源,須要使用相應的Resource實現類,這是比較麻煩的。可是Spring提供了一套強大的加載資源的的機制,不但能夠經過"classpath:","file:"等資源地址前綴識別不一樣的資源類型,還支持Ant風格帶通配符的資源地址。緩存
資源表達式以下圖所示: 安全
##資源加載器session
ResourceLoader接口僅有一個getResource(String location)方阿飛,能夠根據一個資源地址加載文件資源。不過,資源地址僅僅支持帶自u按類型前綴得表達式,不支持Ant風格得資源路徑表達式。ResourcePatternResolver拓展ResourceLoader接口,定義了一個新得接口方法getResources(String locationPattern),該方法支持帶資源類型前綴及Ant風格得資源路徑表達式。PathMathchingResourcePatternResolver是Spring提供得標準實現類。
代碼實現:
package com.flexible.resources; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import java.io.IOException; import java.util.Arrays; import java.util.List; import static junit.framework.TestCase.assertNotNull; public class PatternResolverDemo { public static void main(String[] args) throws IOException { ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); //加載全部類包com.flexible.resources下的,以.xml爲後綴的資源文件 Resource[] resources = resourcePatternResolver.getResources("classpath:com/flexible/resources/**/*.xml"); assertNotNull(resources); List<Resource> resourceList = Arrays.asList(resources); resourceList.forEach(e->{ System.out.println(e.getFilename()); }); } }
提示: 使用Resource操做文件時,若是資源配置文件在項目發佈時會被達到JAR中,,那麼不能使用Resource#getFile()方法,不然會被拋出FileNotFoundException.可是可使用Resource#getInputStream方法讀取。 錯誤的方式: (new DefaultResourceLoader()).getResource("classpath:conf/sys.properties").getFile() 正確的讀取方式: (new DefaultResourceLoader()).getResource("classpath:conf/sys.properties").getInputStream() 在Jar包中getFile()沒法讀取,應該儘可能使用流來處理。
#BeanFactory和ApplicationContext 在Spring中是經過配置文件描述Bean和Bean之間的依賴關係,利用Java語言的反射功能實例化Bean並簡歷 Bean之間的依賴關係。除此以外還提供了Bean的實例緩存,生命週期管理,Bean實例代理,事件發佈,資源裝載等高級服務。 通常稱BeanFactory爲IoC容器,而稱ApplicationContext爲應用上下文,可是爲了方便也將ApplicationContext成爲Spring容器。BeanFactory是面向Spring自己的,ApplicationContext是面向開發者的。
###BeanFactory 能夠被建立和管理的Java對象常被成爲Bean,可是這個JavaBean是要知足必定的規範的,例如須要提供ige默認的不帶參數的構造函數,不依賴於某特定的容器等,可是Spring的Bean比JavaBean更加的普遍一些,因此能夠被Spring容器實例化並甘麗的Java類能夠成爲Bean。
BeanFactory接口位於類結構樹的頂端,它最主要的方法就是getBean(String beanName),該方法從容器中返回特定名稱的Bean.BeanFactory的功能經過其餘接口獲得不斷的拓展。
HierachicalBeanFactory:父子級聯IoC容器的接口,子容器能夠經過接口方法訪問父容器的接口。
getParentBeanFactory containsLocalBean
AutowireCapableBeanFactory:定義了將容器中的Bean按照某種規則(名字,類型匹配等)進行自動裝配的方法。
createBean autowireBean configureBean createBean autowire autowireBeanProperties applyBeanPropertyValues initializeBean applyBeanPostProcessorsBeforeInitialization applyBeanPostProcessorsAfterInitialization destroyBean resolveNamedBean resolveDependency resolveDependency
SingletonBanRegistry:定義容許在運行期間向容器註冊單實例Bean的方法,
registerSingleton getSingleton containsSingleton getSingletonNames getSingletonCount getSingletonMutex
#WebApplicationContext類體結構 WebApplicationContext是專門爲Web準備的,它容許從相對於web根目錄的路徑裝載配置文件完成初始化工做。從WebApplicationContext中能夠得到ServletContext的引用,整個Web應用上下文對象將做爲屬性放置到ServletContext中,以便Web應用環境能夠訪問Spring應用上下文。Spring專門爲此提供了已個工具類WebApplicationContextUtils,經過該類的getWebApplicationContext(ServletContext sc)方法,能夠從ServletContext中獲取WebApplicationContext實例。WebApplicationContext下的Bean除了singleton和prototype兩種做用域以外還有request,session和global session
因爲Web應用比通常的應用有更多的特性,所以WebApplicationContext拓展了ApplicationContext.WebApplicationContext定義了一個常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文起到的時候,WebApplicationContext實例即以此爲鍵放置在ServletContext的屬性列表中,能夠經過如下語句從Web容器中獲取WebApplicationContext:
WebApplication wac = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
這個就是WebApplicationContextUtils工具類getWebApplicationContext(ServletContext sc)方法的內部實現方式,這樣Spring的Web應用上下文就和Web容器上下文應用就能夠實現互訪。
ConfigurableWebApplicationContext拓展了WebApplication,它容許經過配置的方式實例化WebApplicationContext,同時定義了兩個重要的方法
void setServletContext(ServletContext servletContext);爲spring設置web應用上下文,以便兩者結合
void setConfigLocations(String... configLocations);容許加載帶前綴的配置文件
###父子容器
經過HierachicalBeanFactory接口,Spring的IoC容器能夠簡歷父子層級關聯的容器體系,子容器能夠訪問父容器的Bean,可是父容器沒法訪問自容器的內容,SpringMvc中,展示層Bean位於一個子容器中,而業務層和持久層的Bean位於父容器中,這樣展示層就能夠引用業務層和持久層。而業務和持久層看不到展示層的Bean。
#Bean的生命週期
###BeanFactory中Bean的生命週期 具體的過程以下:
1.當調用者經過getBean(beanName)向容器請求某一個Bean時,若是容器註冊了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口,則在實例化Bean以前,將調用postProcessBeforeInstantiation()方法 2.根據配置文件的狀況調用Bean構造函數或者工廠方法實例化Bean。 3.若是容器註冊了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor,那麼實例化Bean以後調用接口postProcessAfterInstantiation()方法,能夠裝載這裏對已經實例化的對象進行一些"裝飾" 4.若是Bean配置了屬性信息,那麼容器在這一步着手將配置文件中的屬性值設置到對應的屬性,設置每一個屬性以前先調用org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口的postProcessPropertyValue()方法。 5.調用Bean的屬性設置方法設置屬性 6.若是Bean實現了org.springframework.beans.factory.BeanNameAware接口,那麼簡化調用setBeanName()接口方法,將配置文件中搞Bean對應的名稱設置到Bean中。 7.若是Bean實現了org.springframework.beans.factory.BeanFactoryAware接口,則將調用setBeanFactory()接口方法,將BeanFactory容器實例設置給Bean。 8.若是BeanFactory裝配了org.springframework.beans.factory.config.BeanPostProcessor後處理器,則將調用 postProcessBeforeInitialization(Object bean, String beanName)接口方法對Bean進行加工操做,bean就是當前須要加工操做的Bean,而BeanName就是當前Bean的配置名。返回的對現貨加工處理後的Bean。這個是實現AOP的重要基石。 9.若是Bean實現了org.springframework.beans.factory.InitializingBean接口則調用 void afterPropertiesSet() 方法 10.若是<bean>中榮光init-method屬性定義了初始化方法,則將執行這個方法。 11.BeanPostProcessor後處理器定義了兩個方法,一.Object postProcessBeforeInitialization(Object bean, String beanName)步驟8調用。二.Object postProcessAfterInitialization(Object bean, String beanName) ,此時調用它能夠得到對Bean的再次加工。 12.做用域是prototype的將返回生成的bean給調用者,調用者負責該bean的生命週期,若是是singleton,那麼則將Bean放入SpringIoC容器的緩衝池中,而且將Bean引用返回給調用者,Spring繼續對這些Bean進行後續的生命週期的維護。 13.做用域是singleton的Bean,當容器關閉,若是實現DisposableBean接口,則將調用接口的destroy()方法,能夠編寫釋放資源,記錄日誌等操做。 14.對於singleton的Bean,若是配置了destroy-method屬性指定了Bean的銷燬方法,那麼會執行該方法釋放資源。
#ApplicationContext中Bean的生命週期