主要內容
- 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容器。
- 通過ApplicationContext類啓動IOC容器
ApplicationContext類繼承了BeanFactory類,實現了更多面嚮應用的功能。
我們就在上例的基礎上,在test/java目錄下,使用TestNG框架再編寫一個ApplicationContextTest類。同樣可以實現像上面兩種加載XML文件啓動IOC容器的方法,此外,ApplicatioinContext類還可以通過類註解的方式加載Bean啓動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文件如下圖所示
在com.czuaphe.webtest包下,編寫SpringBeanServlet類,重寫Servlet的init()方法,得到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裝載各種資源,包括配置文件資源,國際化屬性資源等。
- WritableResource:可寫資源接口,兩個實現類,FileSystemResource和PathResource。
- ByteArrayResource:二進制數組表示資源,二進制數組資源可以在內存中通過程序構造。
- ClassPathResource:類路徑下的資源,資源以相對於類路徑的方式表示,
資源加載
爲了訪問不同的資源必須使用的不同的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。
實例:
<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、任務調度目的。