Spring第一課 IOC容器

主要內容

  • IOC概念和設計思想
  • java反射技術
  • BeanFactory、ApplicationContext以及WebApplicationContext基礎接口
  • Bean的生命週期

IOC

IOC被定義稱作爲控制反轉,主要表示控制類的實例化,通過Spring容器(即Bean配置來進行控制)反轉表示控制權權交給Spring處理,通過java反射技術來進行操控。
說到實際,IOC就是java反射的絕對應用。
IOC有兩種注入方式:

  • 構造函數注入
  • 屬性方法注入
    -接口注入

爲什麼需要三種構造方式呢?有一種不就夠了嗎,有構造參數注入不就可以了嗎?這是因爲並不是每次注入都需要產生特定的角色,屬性注入更加靈活,可以更隨意。
spring的三種注入方式
2018-07-29

spring的依賴注入分爲三種方式

1.構造器注入
2.setter注入
3.接口注入
構造器注入和setter注入是依賴注入的兩種主要方式,接口注入是指從別的地方注入的方式。(通過在xml中描述,實現注入)

一、構造器注入
構造器注入依賴於構造方法的實現,----------構造方法可以是有參數的,也可以是無參數的 。
在沒有spring之前,我們在大多數情況下,我們都是通過構造方法來創建類對象,Spring可以採用反射的方式,通過構造方法來完成注入,這就是構造方法的原理。
1.引入spring的支持
2.通過描述具體的類,構造方法和其中的參數,這樣spring就可以通過相應的信息用反射的方式創建對象。
3.在test文件中加載spring配置文件的方法

String configLocation ="applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
Role role = context.getBean("role", Role.class);

在spring中一切的資源都是bean。

二、spring中最主流的注入方式:setter注入
setter注入利用JAVA Bean規範所定
注意:  構造器注入是通過構造方法注入,setter注入是通過setter方法注入
首先將構造方法設置爲無參的構造方法,然後利用setter注入爲其設置新的值,這也是通過java的反射技術得以實現的
注意:構造器注入和setter注入都是通過java的反射技術得以實現的。

    <!-- 下面是setter注入,需要一個無參的構造方法 -->
     <bean id="role1" class="com.pojo.Role" >
         <property name="id"    value="124"></property>
         <property name="name" value="張三"></property>
         <property name="age" value="2324"></property>
     </bean>

三、spring依賴注入的第三種方式:接口注入
有時候資源並非來自於自身的系統,而是來自於外界,比如說數據庫連接資源完全可以在Tomcat下配置,然後通過JNDI的方式去獲取它,這樣的數據庫連接資源就屬於開發工程外的資源。
接口注入實例

啓動IOC容器方式

  • 通過BeanFactory啓動IOC容器
    BeanFactory類是Spring框架下最核心的接口,它提供了高級的IOC配置機制。我們可以使用下面的XmlBeanDefinitionReader和DefaultListableBeanFactory類啓動IOC容器。
    通過BeanFactory啓動IOC容器
  • 通過ApplicationContext類啓動IOC容器
    ApplicationContext類繼承了BeanFactory類,實現了更多面嚮應用的功能。
    我們就在上例的基礎上,在test/java目錄下,使用TestNG框架再編寫一個ApplicationContextTest類。同樣可以實現像上面兩種加載XML文件啓動IOC容器的方法,此外,ApplicatioinContext類還可以通過類註解的方式加載Bean啓動IOC容器。
    通過ApplicationContext類啓動IOC容器
  • 通過WebApplicationContext類啓動IOC容器
    WebApplicationContext類繼承了ApplicationContext類,專門用於Web應用。啓動方式也是通過Web容器啓動,實現IOC容器的啓動。不能簡單通過Java代碼實現啓動。
    在webapp/WEB-INF下的web.xml中定義ContextLoaderListener監聽Web容器的啓動,然後定義contextConfigLocation獲得Spring框架的Bean配置文件。
    然後在web.xml文件中,再定義一個Servlet,定義它的屬性load-on-startup爲1,表示在Web容器和Spring框架的IOC容器啓動之後自啓動,得到WebApplicationContext類的實例,就可以得到Bean實例了。
    web.xml文件如下圖所示
    web.xml
    在com.czuaphe.webtest包下,編寫SpringBeanServlet類,重寫Servlet的init()方法,得到WebApplicationContext類的實例。
    WebApplicationContext
    編寫了三種IOC容器的啓動方式,在非Web應用下,使用ApplicationContext啓動IOC容器就已經足夠使用,在Web應用下,就必須在web.xml文件中配置WebApplicationContext的啓動。讓Web容器啓動時IOC容器也啓動。BeanFactory類啓動IOC容器一般不常用。

java反射機制

測試類:
public class AppTest{
	private String name;
	private int age;
	private String address;
	
	public AppTest() {
		System.out.println("無參構造函數--");
	}
	public AppTest(String name,int age) {
		System.out.println("有參構造函數**");
	}
	public void message(String name,int age,String address){
		System.out.println("姓名:"+name+"##"+"年齡:"+age+"##"+"地址:"+address);
	}
}

反射獲取測試類:
public class MyTest{
	
	public static void main(String[] arg) throws Exception {
		ClassLoader loader=Thread.currentThread().getContextClassLoader();
		Class clazz=loader.loadClass("com.spring.AppTest");
		//Class clazz=Class.forName("com.spring.AppTest");
		AppTest appTest=(AppTest) clazz.newInstance();
		Method m=clazz.getMethod("message", String.class,int.class,String.class);
		m.invoke(appTest, "zhangsan",17,"beijng");
	}
}
結果:
無參構造函數--
姓名:zhangsan##年齡:17##地址:beijng

類裝載器ClassLoader
類裝載器工作機制:
類的裝載器就是尋找類的字節碼文件並構造出類在JVM內部表示對象組件,在java中,類裝載器把一個類裝入JVM中,需要經過一下步驟:

  • (1)裝載:查找和導入Class文件。
  • (2)鏈接:執行校驗、準備和解析步驟,其中解析步驟是可以選擇的。
  • -校驗:檢查載入Class文件的正確性。
  • -準備:給類的靜態變量分配存儲空間。
  • -解析:將符號引用轉換爲直接引用。
  • (3)初始化:對類的靜態變量、靜態代碼塊執行初始化工作。
    類的加載工作
    全盤委託機制

資源訪問利器

資源抽象接口
JDK所提供的資源的類(如java.net.URL,File等),並不能很好的滿足各種底層資源訪問需求,比如缺少從類路徑或者Web容器上下文中獲取資源的操作類。
於是Spring設計了一個Resource接口,它爲應用程序提供了更強的底層資源訪問能力。該接口擁有對應不同資源的實現。
Resource主要方法實現:
boolean exists():資源是否存在
boolean isOpen():資源是否打開
URL getURL() throws IOException:如果底層資源可以表示成URL,則該方法返回對應的URL對象。
File getFile() throws IOException:如果底層資源對應一個文件,則該方法返回對應的File對象。
InputStream getInputStream() throws IOException:返回資源對應的輸入流。
Resource在起着不可或缺的作用,Spring框架使用Resource裝載各種資源,包括配置文件資源,國際化屬性資源等。
Resource及其實現類的關係

  • WritableResource:可寫資源接口,兩個實現類,FileSystemResource和PathResource。
  • ByteArrayResource:二進制數組表示資源,二進制數組資源可以在內存中通過程序構造。
  • ClassPathResource:類路徑下的資源,資源以相對於類路徑的方式表示,
    Resource及其實現類的關係
    資源加載
    爲了訪問不同的資源必須使用的不同的Resource實現類,還是比較麻煩的。是否可以在不顯式使用Resource實現類的情況下,僅通過資源地址的特殊標識就可以訪問相應的資源呢?Spring提供了一個強大的資源加載機制,不但能夠通過

*後續繼續更新

BeanFactory和ApplicationContext

Spring通過一個配置文件描述Bean及Bean之間的關係,利用java語言的反射功能實例化Bean,並建立Bean之間的依賴關係,Spring的IOC容器在完成這些底層的工作基礎上,還提供了Bean的實例緩存、聲明週期管理、Bean的實例代理、事件發佈、資源裝載等高級服務。
Bean工廠(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,它提供了高級IOC配置機制,BeanFactory使管理不同類型的java對象成爲可能。
應用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory的基礎之上,提供了更多面嚮應用的功能,它提供了國際化支持和框架事件體系,更易於創建實際應用。
我們一般稱BeanFactory爲IOC容器,而稱ApplicationContext爲應用上下文。
對於二者的用途,我們可以進行簡單的劃分:BeanFactory是Spring框架的基礎設施,面向Spring本身;ApplicationContext面向使用Spring框架的開發者,幾乎所有的應用場合都可以直接使用ApplicationContext而非底層的BeanFactory。

BeanFactory

Beanfactory是一個類工廠,但和傳統的類工廠不同,傳統的類工廠僅負責構造一個或幾個類的實例,而BeanFactory是類的通用工廠,它可以創建並管理各種類對象,這些被創建和管理的對象本身沒有什麼特別之處,僅僅是一個POJO,Spring稱這些被創建和管理的java對象爲Bean。我們知道javaBean是要滿足一定規範的,如必須提供一個默認不帶參的構造函數,不依賴於某一特定的容器等,但Spring中所說的Bean比javaBean更寬泛一些,所以可以被Spring容器實例化並管理的Java類都可以成爲Bean。
BeanFactory的體系結構
Spring爲BeanFactory提供了多種實現,最常用的是XmlBeanFactory,但現在已經廢棄,建議使用XmlBeanDefinitionRead、DefaultListableBeanFactory代替。
BeanFactory接口位於類結構樹的頂端,它最主要的方法就是getBean(String beanName),該方法從容器中,返回特定名稱的Bean。
BeanFactory涉及的接口
BeanFactory涉及的接口

實例:
<bean id="appTest" class="com.spring.AppTest"
		p:name="cui"
		p:age="18"
		p:address="beijing" />

public class AppTest{
	private String name;
	private int age;
	private String address;
	
	public AppTest() {
		System.out.println("無參構造函數--");
	}
	public AppTest(String name,int age) {
		System.out.println("有參構造函數**");
	}
	public void message(String name,int age,String address){
		System.out.println("姓名:"+name+"##"+"年齡:"+age+"##"+"地址:"+address);
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getString() {
		// TODO Auto-generated method stub
		return this.name+" "+this.age+" "+this.address;
	}
}

/**
 * 測試
 */
public class MyTest{
	
public static void main(String[] arg) throws Exception {
	ResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
	Resource resource=resolver.getResource("classpath:applicationContext.xml");
	System.out.println(resource.getURL());
	DefaultListableBeanFactory dBeanFactory=new DefaultListableBeanFactory();
	XmlBeanDefinitionReader xReader=new XmlBeanDefinitionReader(dBeanFactory);
		xReader.loadBeanDefinitions(resource);
		System.out.println("init BeanFactory");
		AppTest app=(AppTest) dBeanFactory.getBean("appTest");
		String s=app.getString();
		System.out.println(s);
	}
}
結果:
file:/D:/EclipseWorkSpace/spring/target/classes/applicationContext.xml
init BeanFactory
無參構造函數--
cui 18 beijing

XmlBeanDefinitionReader通過Resource裝載Spring配置信息並啓動IOC容器,然後就可以通過
BeanFactory#getBean(beanName)方法從IOC容器獲取Bean。通過BeanFactory啓動IOC容器時,並
不會初始化配置文件中定義Bean,初始化動作發生在第一次調用時,對於單例的Bean來說,BeanFactory會
緩存Bean的實例,所以第二次使用getBean()獲取Bean時,將直接從IOC容器的緩存中獲取Bean實例。
Spring在DefaultSingletonBeanRegistry類中提供了一個用於緩存單實例Bean的緩存器,它是一個用
HashMap實現的緩存器,單實例Bean以beanName爲鍵保存在這個HashMap中。

需要注意的是:在初始化BeanFactory時,必須爲其提供一種日誌框架,我們使用Log4J,即在類路徑下
提供Log4j配置文件,這樣啓動Spring容器纔不會報錯。

ApplicationContext介紹
如果說BeanFactory是Spring的心臟,那麼ApplicationContext就是完整的身軀了。ApplicationContext由BeanFactory派生而來,提供了更多面向實際的功能,在BeanFactory中,很多功能以編程的方式實現,而在ApplicationContext中則可以通過配置的方式實現。
1.ApplicationContext類體系結構:
ApplicationContext的主要實現類是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext前者默認從類路徑加載配置文件,後者默認從文件系統中裝載配置文件。
ApplicationContext繼承了HierarchicalBeanFactory和ListableBeanFactory接口,在此基礎上,還通過其他接口拓展了BeanFactory的功能。

  • ApplicationEventPublisher:讓容器擁有發佈上下文事件的功能,包括容器的啓動事件和關閉事件等。實現了ApplicationListener事件監聽接口的Bean可以接收到容器事件,並對時間進行響應處理,在ApplicationContext抽象實現類AbstractApplicationContext中存在一個ApplicationEventMulticaster,它負責保存所有的監聽器。以便在容器產生上下文事件時,通知這些事件監聽者。
  • MessageSource:爲應用提供i18n國際化消息訪問功能。
  • ResourcePatternResolver:所有的ApplicationContext實現類都實現了類似於PathMatchingResourcePatternResolver的功能。可以通過帶前綴的Ant風格的資源文件路徑裝載Spring配置文件。
  • LifeCycle:該接口提供了start()和stop()兩個方法,主要控制異步處理過程,再具體使用中,該接口同時被ApplicationContext實現和具體的Bean實現。ApplicationContext會將start/stop的信息傳遞給容器中,所有實現了該接口的Bean已達到管理和控制JMX、任務調度目的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章