精通Spring+4.x++企業開發與實踐之IOC容器

#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的功能經過其餘接口獲得不斷的拓展。

    • ListableBeanFactory:該接口定義了訪問容器中Bean基本信息的若干方法,例如查看Bean的個數,獲取某一類型的Bean配置名,查看容器是否包括某一個Bean等。 containsBeanDefinition getBeanDefinitionCount getBeanDefinitionNames getBeanNamesForType getBeanNamesForType getBeanNamesForType getBeansOfType getBeansOfType getBeanNamesForAnnotation getBeansWithAnnotation findAnnotationOnBean
    • HierachicalBeanFactory:父子級聯IoC容器的接口,子容器能夠經過接口方法訪問父容器的接口。

      getParentBeanFactory
      containsLocalBean
    • CofigurableBeanFactory:這是一個重要的接口加強了IoC容器的可定製性。它定義了設置類裝載器的,屬性編輯器,容器初始化後置處理器等方法。 setParentBeanFactory setBeanClassLoader getBeanClassLoader setTempClassLoader getTempClassLoader setCacheBeanMetadata isCacheBeanMetadata setBeanExpressionResolver getBeanExpressionResolver setConversionService getConversionService addPropertyEditorRegistrar registerCustomEditor copyRegisteredEditorsTo setTypeConverter getTypeConverter addEmbeddedValueResolver hasEmbeddedValueResolver resolveEmbeddedValue addBeanPostProcessor getBeanPostProcessorCount registerScope getRegisteredScopeNames getRegisteredScope getAccessControlContext copyConfigurationFrom registerAlias resolveAliases getMergedBeanDefinition isFactoryBean setCurrentlyInCreation isCurrentlyInCreation registerDependentBean getDependentBeans getDependenciesForBean destroyBean destroyScopedBean destroySingletons
    • AutowireCapableBeanFactory:定義了將容器中的Bean按照某種規則(名字,類型匹配等)進行自動裝配的方法。

      createBean
      autowireBean
      configureBean
      createBean
      autowire
      autowireBeanProperties
      applyBeanPropertyValues
      initializeBean
      applyBeanPostProcessorsBeforeInitialization
      applyBeanPostProcessorsAfterInitialization
      destroyBean
      resolveNamedBean
      resolveDependency
      resolveDependency
    • SingletonBanRegistry:定義容許在運行期間向容器註冊單實例Bean的方法,

      registerSingleton
      getSingleton
      containsSingleton
      getSingletonNames
      getSingletonCount
      getSingletonMutex
    • BeanDefinitionRegistry:Spring配置文件中每個<bean></bean>節點元素在Spring容器裏都經過一個BeanDefinition對象標識,它描述了Bean的配置信息,而BeanDefinitionRegistry接口提了向容器手工註冊BeanDefinition對象的方法。 registerBeanDefinition removeBeanDefinition getBeanDefinition containsBeanDefinition getBeanDefinitionNames getBeanDefinitionCount isBeanNameInUse

#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的銷燬方法,那麼會執行該方法釋放資源。

代碼實例連接: https://github.com/chenanddom/SpringSection4/tree/master/src/main/java/com/flexible/beanfactory/beanfactorylifecyle

#ApplicationContext中Bean的生命週期

相關文章
相關標籤/搜索