spring初學 摘記
spring簡介
Spring的核心是個輕量級容器(container),實現了IoC(Inversion of Control)模式的容器,Spring的目標是實現一個全方位的整合框架,在Spring框架下實現多個子框架的組合,這些子框架之間彼此可以獨立,也可以使用其它的框架方案加以替代,Spring希望提供one-stop shop的框架整合方案
Spring是一個輕量級的控制反轉(IOC)和麵向切面(AOP)的容器框架。
輕量——從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個大小隻有1MB多的JAR檔案裡釋出。並且Spring所需的處理開銷也是微不足道的。
此外,Spring是非侵入式的:典型地,Spring應用中的物件不依賴於Spring的特定類。
控制反轉——Spring通過一種稱作控制反轉(IoC)的技術促進了鬆耦合。當應用了IoC,一個物件依賴的其它物件會通過被動的方式傳遞進來,而不是這個物件自己建立或者查詢依賴物件。你可以認為IoC與JNDI相反——不是物件從容器中查詢依賴,而是容器在物件初始化時不等物件請求就主動將依賴傳遞給它。
面向切面——Spring提供了面向切面程式設計的豐富支援,允許通過分離應用的業務邏輯與系統級服務(例如審計(auditing)和事務(transaction)管理)進行內聚性的開發。應用物件只實現它們應該做的——完成業務邏輯——僅此而已。它們並不負責(甚至是意識)其它的系統級關注點,例如日誌或事務支援。
容器——Spring包含並管理應用物件的配置和生命週期,在這個意義上它是一種容器,你可以配置你的每個bean如何被建立——基於一個可配置原型(prototype),你的bean可以建立一個單獨的例項或者每次需要時都生成一個新的例項——以及它們是如何相互關聯的。然而,Spring不應該被混同於傳統的重量級的EJB容器,它們經常是龐大與笨重的,難以使用。
框架——Spring可以將簡單的元件配置、組合成為複雜的應用。在Spring中,應用物件被宣告式地組合,典型地是在一個XML檔案裡。Spring也提供了很多基礎功能(事務管理、持久化框架整合等等),將應用邏輯的開發留給了你。所有Spring的這些特徵使你能夠編寫更乾淨、更可管理、並且更易於測試的程式碼。它們也為Spring中的各種模組提供了基礎支援。
spring框架組成
Spring 框架是一個分層架構,由 7 個定義良好的模組組成。Spring 模組構建在核心容器之上,核心容器定義了建立、配置和管理 bean 的方式,如下圖所示:
Spring 框架的分為7個模組,組成 Spring 框架的每個模組(或元件)都可以單獨存在,或者與其他一個或多個模組聯合實現。每個模組的功能如下:
1.核心容器:核心容器提供 Spring 框架的基本功能,核心模組提供了框架的基本組成部分,包括 IoC 和依賴注入功能。核心容器的主要元件是 BeanFactory,它是工廠模式的實現。BeanFactory 使用控制反轉 (IOC) 模式將應用程式的配置和依賴性規範與實際的應用程式程式碼分開。
2.Spring 上下文:Spring 上下文是一個配置檔案,向 Spring 框架提上下文資訊。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和排程功能。
3.Spring AOP:通過配置管理特性,Spring AOP 模組直接將面向方面的程式設計功能整合到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何物件支援 AOP。Spring AOP 模組為基於 Spring 的應用程式中的物件提供了事務管理服務。通過使用 Spring AOP,不用依賴 EJB 元件,就可以將宣告性事務管理整合到應用程式中。
4. Spring DAO:JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同資料庫供應商丟擲的錯誤訊息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫的異常程式碼數量(例如開啟和關閉連線)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。
5.Spring ORM:Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的物件關係工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。
6. Spring Web 模組:Web 上下文模組建立在應用程式上下文模組之上,為基於 Web 的應用程式提供了上下文。所以,Spring 框架支援與 Jakarta Struts 的整合。Web 模組還簡化了處理多部分請求以及將請求引數繫結到域物件的工作。
7. Spring MVC 框架:MVC 框架是一個全功能的構建 Web 應用程式的 MVC 實現。通過策略介面,MVC 框架變成為高度可配置的,MVC 容納了大量檢視技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。
總結起來,Spring有如下優點:
1.低侵入式設計,程式碼汙染極低
2. 獨立於各種應用伺服器,可以真正實現Write Once,Run Anywhere的承諾
3.Spring的DI機制降低了業務物件替換的複雜性
4.Spring並不完全依賴於Spring,開發者可自由選用Spring框架的部分或全部
IOC 和 AOP:這兩個概念可以算是spring中的核心
控制反轉模式(也稱作依賴性介入)的基本概念是:不建立物件,但是描述建立它們的方式。在程式碼中不直接與物件和服務連線,但在配置檔案中描述哪一個元件需要哪一項服務。容器 (在 Spring 框架中是 IOC 容器) 負責將這些聯絡在一起。在典型的 IOC 場景中,容器建立了所有物件,並設定必要的屬性將它們連線在一起,決定什麼時間呼叫方法。
控制反轉:當某個java 物件需要(依賴)另一個java 物件時,不是自身直接建立依賴物件,而是由實現IoC 的容器(如spring 框架的IoC容器)來建立,並將它注入需要這個依賴物件的java 物件中。
型別 1 |
服務需要實現專門的介面,通過介面,由物件提供這些服務,可以從物件查詢依賴性(例如,需要的附加服務),這種用的很少 |
型別 2 |
通過 JavaBean 的屬性(例如 setter 方法)分配依賴性 |
型別 3 |
依賴性以建構函式的形式提供,不以 JavaBean 屬性的形式公開 |
Spring 框架的 IOC 容器主要採用型別 2 和型別3 實現。
面向方面的程式設計,即 AOP,是一種程式設計技術,它允許程式設計師對橫切關注點或橫切典型的職責分界線的行為(例如日誌和事務管理)進行模組化。AOP 的核心構造是方面,它將那些影響多個類的行為封裝到可重用的模組中。
aop就是縱向的程式設計,如下圖所示,業務1和業務2都需要一個共同的操作,與其往每個業務中都新增同樣的程式碼,不如寫一遍程式碼,讓兩個業務共同使用這段程式碼。
spring中面向切面變成的實現有兩種方式,一種是動態代理,一種是CGLIB,動態代理必須要提供介面,而CGLIB實現是有繼承。
AOP(Aspect-OrientedProgramming)面向方面程式設計,與OOP完全不同,使用AOP程式設計系統被分為方面或關注點,而不是OOP中的物件。
在OOP面向物件的使用中,無可避免的會出現程式碼重複,而且使用面向物件的程式設計方式,這種重複無法避免,比如使用者許可權判斷中,根據相應的許可權執行相應的方法;在servlet中設定編碼格式時,同樣相同的程式碼出現很多次,而且還根業務無關,很容易忘記寫,結果執行的時候就出現亂碼拉。這種重複程式碼不僅使編碼麻煩,而且還不容易維護。而AOP則將這些程式碼整理起來,將解決某個切面問題的程式碼單獨的放在某個模組中,然後再織入到程式中。
AOP中的術語
Aspect:橫切面的功能, 抽象出類,或介面, AOP程式設計重要的就是識別出橫切面功能。(方面,類似於字元編碼功能)
Advice: 橫切面功能的具體實現,需要根據實際的情況分析,如果在目標物件操作之前是 before在操作之後,就是 afteradvice(增強,類似於字元編碼過濾器)
Pointcut:切入點,描述橫切面功能應用的限制,不是所有的流程都需要,那些可以使用的地方就是切入點(類似於過濾器的匹配規則 /*)
Joinpoint: 連線點,或指元件加入流程的時機,比如設定屬性,呼叫方法,等,Spring只支援方法呼叫的連線點,而其他的一些框架支援屬性的連線點如:AspectJ,(類似於過濾器的過濾規則 REQUEST,FORWARD)
Weave: 縫合,將元件應用到業務流程中的這個過程,叫縫合或織入。
(類似於將過濾器配置到web.xml檔案的過程)
Proxy,代理,在實現上,Spring的AOP其實就是使用JDK的動態代理(使用介面的方式完成代理操作),也可以使用CGLIB(使用繼承的方式完成代理操作)。
Target,目標,業務操作的實際物件
例項:設定字元編碼格式看作是一個Aspect方面,而攔截器就是一個Advice增強。
<span style="font-size:18px;"><!-- 字元編碼過濾器-->
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>com.bjpowernode.egov.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
</span>
過濾器類
<span style="font-size:18px;">public class CharacterEncodingFilter implements Filter {
@Override
public void destroy() {}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChainchain) throws IOException, ServletException {
request.setCharacterEncoding("GB18030");
chain.doFilter(request,response);
}
@Override
publicvoid init(FilterConfig filterConfig) throws ServletException {}
}</span>
這樣就不用在每個servlet中設定編碼拉。。
spring框架中AOP的使用
1,拷貝jar包
2,spring配置檔案中增加名稱空間和約束檔案
啟用aop功能:就把標籤新增進來就可以拉。
3,寫被代理的類和擴充套件類
4,由配置檔案宣告
<!--宣告目標類-->
<bean id="targetclass" class="com.spring.aop.TargetClass"></bean>
<!--宣告擴充套件類-->
<bean id="extendsclass" class="com.spring.aop.extendsClass"></bean>
<!--織入擴充套件類,並宣告在哪個方法上執行擴充套件類-->
<aop:config>
<aop:aspect id="extendAspect" ref="">
<aop:pointcut expression="execution(public ** (..))" id="extendsPoincat">
<!--在目標方法執行前執行的方法-->
<aop:before method="beforemethod" pointcut-ref="extendsPoincat" />
<!--在目標方法執行後執行的方法-->
<aop:after method="aftermethod" pointcut-ref="extendsPoincat" />
</aop:aspect>
</aop:config></span>
5,測試
成功的話,執行目標類中的目標方法targetmethod()時,會先執行擴充套件類中的beforemethod()方法,再執行目標方法,最後再執行aftermethod()方法。
也就是我們只需要手動呼叫targetmethod方法,擴充套件類中的兩個方法框架會在執行的時候通過讀取配置檔案,獲取相應資訊,自動給我們新增上擴充套件的方法。。
測試肯定成功,不相信的話,可以自己試試。
Spring框架中使用AOP的優點
Aop與spring的IOC容器整合,增強,切入點都是javabean,可以在同一檔案中配置和spring的其他部分一樣,可以在不同應用伺服器之間任意移植
spring實現Aop的攔截介面,使得使用者不必繫結在特定的攔截器介面上。
aop面向切面的程式設計思想,打破面向物件的思維方式,我們要學習的不僅是aop的使用,更要學習面向切面的這種思想。
AOP 和 IOC 是補充性的技術,它們都運用模組化方式解決企業應用程式開發中的複雜問題。在典型的面向物件開發方式中,可能要將日誌記錄語句放在所有方法和 Java 類中才能實現日誌功能。在 AOP 方式中,可以反過來將日誌服務模組化,並以宣告的方式將它們應用到需要日誌的元件上。當然,優勢就是 Java 類不需要知道日誌服務的存在,也不需要考慮相關的程式碼。所以,用 Spring AOP 編寫的應用程式程式碼是鬆散耦合的。AOP 的功能完全整合到了 Spring 事務管理、日誌和其他各種特性的上下文中。
IOC 容器:Spring 設計的核心是 org.springframework.beans 包,它的設計目標是與 JavaBean 元件一起使用。這個包通常不是由使用者直接使用,而是由伺服器將其用作其他多數功能的底層中介。下一個最高階抽象是 BeanFactory 介面,它是工廠設計模式的實現,允許通過名稱建立和檢索物件。BeanFactory 也可以管理物件之間的關係。
spring 的容器
spring 管理的基本單元是Bean,在spring 的應用中,所有的元件都是一個個的Bean,它可以是任何的java 物件。spring 負責建立這些Bean的例項。並管理生命週期。而spring 框架是通過其內建的容器來完成Bean 的管理的,Bean 在spring 的容器中生存著,使用時只需要通過它提供的一些方法從其中獲取即可。
spring 的容器有兩個介面:BeanFactory 和ApplicationContext 這兩個介面的例項被陳為spring 的上下文。
ApplicationContext ac = newClassFathXmlApplicationContext("app*.xml");
AccountService accountService =(AccountService)ac.getBean("accountServiceImpl");</span>
注:由於ApplicationContext是基於BeanFactory之上的,所以,一般ApplicationContext功能比較強大,建議使用ApplicationContext經常用到的三個實現:
1.ClassPathXmlApplicationContext:從類路徑中的XML檔案載入上下文定義資訊。把上下文定義檔案當成類路徑資源。
2.FileSystemXmlApplicationContext:從檔案系統中的XML檔案載入上下文定義資訊。
3.XmlWebApplicationContext:從Web系統中的XML檔案載入上下文定義資訊。
BeanFactory 支援兩個物件模型:
1.單態 模型提供了具有特定名稱的物件的共享例項,可以在查詢時對其進行檢索。Singleton 是預設的也是最常用的物件模型。對於無狀態服務物件很理想。
2. 原型 模型確保每次檢索都會建立單獨的物件。在每個使用者都需要自己的物件時,原型模型最適合。
bean 工廠的概念是 Spring 作為 IOC 容器的基礎。IOC 將處理事情的責任從應用程式程式碼轉移到框架。正如我將在下一個示例中演示的那樣,Spring 框架使用 JavaBean 屬性和配置資料來指出必須設定的依賴關係。
1 Spring中的事務處理
2 ioc容器在Web容器中的啟動
3 Spring JDBC
4 Spring MVC
5 Spring AOP獲取Proxy
6 Spring宣告式事務處理
7 Spring AOP中對攔截器呼叫的實現
8 Spring驅動Hibernate的實現
9 Spring Acegi框架鑑權的實現
spring的例項
第 1 步:建立 Java 專案
第 2 步:新增必需的庫
第 3 步:建立原始檔
HelloWorld.java 和 MainApp.java 檔案
這裡是 HelloWorld.java 檔案的內容:
package com.tutorialspoint;
public class HelloWorld {
private String message;
public void setMessage(Stringmessage){
this.message = message;
}
public void getMessage(){
System.out.println("YourMessage : " + message);
}
}
下面是第二個檔案 MainApp.java 的內容:
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public staticvoid main(String[] args) {
ApplicationContext context =
newClassPathXmlApplicationContext("Beans.xml");
HelloWorld obj = (HelloWorld)context.getBean("helloWorld");
obj.getMessage();
}
}
第 4 步:建立 bean 的配置檔案
Beans.xml 檔案
<?xml version="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<beanid="helloWorld"class="com.tutorialspoint.HelloWorld">
<propertyname="message" value="Hello World!"/>
</bean>
</beans>
第 5 步:執行程式
自己動手模擬一個spring
首先我們把我們用的dao、service、entity定義出來:
Student.java :
public class Student{
private int number;
private String name;
private String address;
//get set 省略
}
因為spring提倡的就是面向介面程式設計,所以在我們寫dao層和service層具體實現之前,我們先定義介面,讓我們的具體實現實現介面。介面的程式碼很簡單,在這就不貼出來了。
StudentNewDaoImp .java
public classStudentNewDaoImp implements StudentNewDao {
public void add(Student stu) {
System.out.println("stuDao is set andsaved");
}
}<span style="color: red; font-family: "Microsoft YaHei";font-size:14px; background-color: rgb(255, 255, 255);"> </span>
StudentServiceImp.java
public classStudentServiceImp implements StudentService {
//定義dao的例項 沒有new出來
StudentNewDao stuDao=null;
public StudentNewDao getStuDao() {
return stuDao;
}
public void setStuDao(StudentNewDao stuDao) {
this.stuDao = stuDao;
}
@Override
public void add(Student stu) {
stuDao.add(stu);
}
}
這裡要注意的是,我們這裡是模擬spring,主要模擬spring中的IOC功能,所以在此我們一樣要在service層中定義dao的例項,當然不用new出來,我們就通過spring的IOC把這裡的dao層注入進來。
不要忘了對dao提供set。Get方法,因為IOC的底層其實就是利用反射機制實現的,他把dao注入進來,其實底層就是通過反射set進來的。
好了,我們所需的dao層、service層還有entity定義好了之後,萬事俱備只欠東風了,下一步我們就是定義我們自己的ClassPathXmlApplicationContext類了,通過他,在我們new出他的物件的時候,他來載入配置檔案,然後把我們的dao操作注入到我們的service層,
在spring中,ClassPathXmlApplicationContext類實現了BeanFactory介面,在此我們也定義一個BeanFactory介面,其實這個介面沒什麼具體的作用,我們就是為了來模擬spring。在定義這個介面和實現類之前,我們先來看一下我們所需的xml是怎麼編寫的,下面我們就具體來看一下beans.xml的配置:
Beans.xml:
<beans>
<bean id="stuDao" class="com.bzu.dao.imp.StudentDaoImp" />
<bean id="stuService" class="com.bzu.service.imp.StudentServiceImp" >
<property name="stuDao" bean="stuDao"/>
</bean>
</beans> <span style="font-family: "Microsoft YaHei";font-size:14px; background-color: rgb(255, 255, 255);"> </span>
看到這,相信大家都能感覺到這個配置檔案太簡單了,沒有spring中那麼多繁瑣的配置,當然啦,我們這是隻是實現其中的一個功能,spring提供了很多那麼強大的功能,配置當然繁瑣一些了。相信上邊的程式碼不用我解釋大家也能看懂了吧。
好了,配置檔案我們看完了,下一步我們一起來看一下我們的spring容器——
ClassPathXmlApplicationContext具體是怎麼實現的,
我們首先還是來看一下他的介面定義:
BeanFactory.java:
public interface BeanFactory {
public Object getBean(String id);
}
我們看到,介面其實很簡單,就定義了一個getBean方法,下面我們來看一下具體的實現類:
ClassPathXmlApplicationContext.java
public classClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beans =new HashMap<String, Object>();
public ClassPathXmlApplicationContext()throws Exception, Exception {
//把xml中的bean解析出來
SAXBuilder sb = new SAXBuilder();
Document doc =sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml"));//構造文件物件
Element root = doc.getRootElement(); //獲取根元素HD
List list =root.getChildren("bean");// 取名字為disk的所有元素
for (int i = 0; i < list.size();i++) {
Element element = (Element)list.get(i);
String id =element.getAttributeValue("id");
String clazz =element.getAttributeValue("class");
Object o =Class.forName(clazz).newInstance();
System.out.println(id + " :" + clazz);
beans.put(id, o);
for (Element propertyElement :(List<Element>) element.getChildren("property")) {
String name =propertyElement.getAttributeValue("name"); // userDAO stuDao
String bean =propertyElement.getAttributeValue("bean"); // u stuDao
Object beanObject =beans.get(bean);// UserDAOImpl instance com.bzu.dao.StudentNewDaoImp
System.out.println("Object: " + beanObject.getClass().getSimpleName());
String methodName ="set" + name.substring(0, 1).toUpperCase()
+ name.substring(1);
System.out.println("methodname = " + methodName); //設定stuDao變為setStuDao 從而反射獲得這個函式
Method m =o.getClass().getMethod(methodName,
beanObject.getClass().getInterfaces()[0]);
System.out.println("methodname = " + m.getName());
m.invoke(o, beanObject);
}
}
}
@Override
public Object getBean(String id) {
return beans.get(id);
}
}
解釋一下這段程式碼:
首先我們定義了一個容器Map<String, Object> beans,這個容器的作用就是用來裝我們從配置檔案裡解析來的一個個bean,為什麼要用map型別,我想大家也差不多能猜到吧,我們配置檔案中每一個bean都有一個id來作為自己的唯一身份。我們把這個id存到map的key裡面,然後value就裝我們的具體bean物件。
說完這個容器之後,下面我們在來看一下ClassPathXmlApplicationContext的構造方法,這個構造方法是我們spring管理容器的核心,這個構造方法的前半部分是利用的jdom解析方式,把xml裡面的bean一個個的解析出來,然後把解析出來的bean在放到我們bean容器裡。
我們下面在來看一下這個構造的方法,後半部分主要是在對配置檔案進行解析出bean的同時去檢視一下這個bean中有沒有需要注射bean的,如果有的話,他就去通過這些裡面的property屬性獲取他要注射的bean名字,然後構造出set方法,然後通過反射,呼叫注入bean的set方法,這樣我們所需要的bean就被注入進來了。如果這段程式碼你看不懂的話,那你只能去看一下有關反射的知識了。最後我們就來看一下實現介面的getBean放了,其實這個方法很簡單,就是根據提供的bean的id,從bean容器內把對應的bean取出來。
好了,我們所需的東西都定義好了,下面我們據來測試一下,看看我們自己模仿的spring到底能不能自動把我們所需要的dao層給我們注入進來。
public class Test {
public static void main(String[] args)throws Exception {
ClassPathXmlApplicationContext context= new ClassPathXmlApplicationContext();
Student stu = new Student();
StudentService service =(StudentService) context.getBean("stuService");
//作用同上 例項化一個service然後service設定一個例項化的StuDao
// StudentServiceImp service = newStudentServiceImp();
// service.setStuDao(new StudentNewDaoImp());
service.add(stu);
}
}
執行程式碼,控制檯輸出:
stuDao :com.bzu.dao.StudentNewDaoImp
stuService :com.bzu.service.StudentServiceImp
Object :StudentNewDaoImp
method name =setStuDao
method name =setStuDao
stuDao is set andsaved
好,成功注入進來,到此,我們模仿的spring就到此結束了,下一篇我們就開始對spring進行一個全面深入瞭解了,敬請期待。
一:spring 的依賴注入
1)、構造器注入
<bean id="accoutDaoImpl" class="cn.csdn.dao.AccoutDaoImpl" scope=”singleton”/>
<bean id="accoutServicImpl" class="cn.csdn.service.AccoutServicImpl" scope=”">
<!-- 構造方法注入方式-->
<constructor-arg ref="accoutDaoImpl"/>
</bean></span>
注:這種注入方式很少用,如果是注入物件一般為上例注入,但有時要注入基本資料型別,一般用下面方法注入
<constructor-arg>
<value>hello world!</value>
</constructor-arg></span>
如果構造方法不只一個引數時,應指明所注入引數的索引或者資料型別,例如:
<constructor-arg index="0" type="java.lang.String">
<value>sunDriver</value>
</constructor-arg>
<constructor-arg index="1" type="java.lang.String">
<value>jdbc:odbc:School</value>
</constructor-arg></span>
2)、設值(set 方法)注入
<bean id="accountDaoImpl"
class="cn.csdn.dao.AccoutDaoImpl"/>
<bean id="accoutServicImpl"
class="cn.csdn.service.AccoutServicImpl">
<!-- 設值(set 方法)注入-->
<property name="accountDaoImpl" ref="accoutDaoImpl"/>
</bean></span>
注:<property name="accountDaoImpl" ref="accoutDaoImpl"/>
相當於呼叫set AccountDaoImpl方法,把值設為accoutDaoImpl
3)介面注入(很少用)
二: xml 裝配Bean屬性含義
1.id:指定該Bean 的唯一標識。
2.class:指定該Bean 的全限定名。
3.name:為該Bean 指定一到多個別名。多個別名可以用“,”和“;”分割。
4.autowire:指定該Bean 的屬性的裝配方式。
所謂自動裝配是指在<BEAN>標籤中不用指定其依賴的BEAN,而是通過配置的自動裝配來自動注入依賴的BEAN,這種做法讓我們的配置更加簡單。
1)no:不使用自動裝配。必須通過ref 元素指定依賴,這是預設設定。由於顯式指定協作者可以使配置更靈活、更清晰,因此對於較大的部署配置,推薦採用該設定。而且在某種程度上,它也是系統架構的一種文件形式。
<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton">
<property name="studentDaoImpl"
ref="studentDaoImpl">
</property>
</bean></span>
備註:有property 屬性指定ref
2)byName:根據屬性名自動裝配。此選項將檢查容器並根據名字查詢與屬性完全一致的bean,並將其與屬性自動裝配。
例如,在bean 定義中將autowire設定為by name,而該bean 包含master 屬性(同時提供setMaster(..)方法),Spring 就會查詢名為master 的bean 定義,並用它來裝配給master 屬性。
<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton" autowire="byName"/>
備註:沒有property 屬性
3)byType:如果容器中存在一個與指定屬性型別相同的bean,那麼將與該屬性自動裝配。如果存在多個該型別的bean,那麼將會丟擲異常,並指出不能使用byType 方式進行自動裝配。若沒有找到相匹配的bean,則什麼事都不發生,屬性也不會被設定。如果你不希望這樣,那麼可以通過設定dependency-check="objects"讓Spring 丟擲異常。
備註:spring3.0 以上不拋異常。
<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton" autowire="byType"/>
備註:沒有property 屬性
4)Constructor:與byType 的方式類似,不同之處在於它應用於構造器引數。如果在容器中沒有找到與構造器引數型別一致的bean,那麼將會丟擲異常。
<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton"autowire="constructor"/>
備註:沒有property 屬性
5)autodetect:通過bean 類的自省機制(introspection)來決定是使用constructor 還是byType 方式進行自動裝配。如果發現預設的構造器,那麼將使用byType 方式。
<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton" autowire="autodetect"/>
5.scope:指定該Bean 的生存範圍
scope用來宣告IOC容器中的物件應該處的限定場景或者說該物件的存活空間,即在IOC容器在物件進入相應的scope之前,生成並裝配這些物件,在該物件不再處於這些scope的限定之後,容器通常會銷燬這些物件。
1) singleton型別的bean定義,在一個容器中只存在一個例項,所有對該型別bean的依賴都引用這一單一例項
2) scope為prototype的bean,容器在接受到該型別的物件的請求的時候,會每次都重新生成一 個新的物件給請求方,雖然這種型別的物件的例項化以及屬性設定等工作都是由容器負責的,但是隻要準備完畢,並且物件例項返回給請求方之後,容器就不在擁有 當前物件的引用,請求方需要自己負責當前物件後繼生命週期的管理工作,包括該物件的銷燬
3) request ,session和global session
這三個型別是spring2.0之後新增的,他們只適用於web程式,通常是和XmlWebApplicationContext共同使用
request:
<bean id ="requestPrecessor" class="...RequestPrecessor" scope="request" />
Spring容器,即XmlWebApplicationContext 會為每個HTTP請求建立一個全新的RequestPrecessor物件,當請求結束後,,該物件的生命週期即告結束
session
<bean id ="userPreferences" class="...UserPreferences" scope="session" />
Spring容器會為每個獨立的session建立屬於自己的全新的UserPreferences例項,他比request scope的bean會存活更長的時間,其他的方面真是沒什麼區別。
global session:
<bean id ="userPreferences" class="...UserPreferences" scope="globalsession" />
global session只有應用在基於porlet的web應用程式中才有意義,他對映到porlet的global範圍的session,如果普通的servlet的web 應用中使用了這個scope,容器會把它作為普通的session的scope對待。
6.init-method:指定該Bean 的初始化方法。
destroy-method:指定該Bean 的銷燬方法。
這個就像servlet中init和destroy方法一樣,只不過這裡在配置檔案配置的
7.abstract:指定該Bean 是否為抽象的。如果是抽象的,則spring 不為它建立例項。
8.parent
如果兩個Bean 的屬性裝配資訊很相似,那麼可以利用繼承來減少重複的配置工作。
<!-- 裝配Bean 的繼承
父類作為模板,不需要例項化,設定abstract=”true”-->
<bean id=”parent” class=”cn.csdn.service.Parent”abstract=”true”>
<property name=”name” value=”z_xiaofei168”/>
<property name=”pass” value=”z_xiaofei168”/>
</bean>
<!-- 裝配Bean 的繼承子類中用parent 屬性指定父類標識或別名
子類可以覆蓋父類的屬性裝配,也可以新增自己的屬性裝配
-->
` <bean id=”child” class=”cn.csdn.service.Chlid” parent=”parent”>
<property name=”pass” value=”123123”/>
<property name=”age” value=”22”/>
</bean>
三:裝配Bean 的各種型別屬性值
1..簡單型別屬性值的裝配
<bean id="bean1" class="cn.csdn.domain.Bean1">
<property name="name" value="z_xiaofei168"/>
<property name="age">
<value>22</value>
</property>
</bean></span>
2.引用其他Bean 的裝配
<bean id="bean1" class="cn.csdn.domain.Bean1">
...
</bean>
<bean id="bean2" class="cn.csdn.domain.Bean2">
<!-- 引用自其他Bean 的裝配-->
<property name="bean1" ref="bean1"/>
</bean></span>
另外一種不常使用的配置方式是在property 元素中嵌入
一個bean 元素來指定所引用的Bean.
<bean id="bean1" class="cn.csdn.domain.Bean1">
...
</bean>
<bean id="bean2" class="cn.csdn.domain.Bean2">
<!-- 引用自其他Bean 的裝配-->
<property name="bean1">
<bean id="bean1"
class="cn.csdn.domain.Bean1"/>
</property>
</bean></span>
3.集合的裝配
其實集合的裝配並不是複雜,反而感覺到很簡單,用一個例子來說明問題吧:
四:Spring bean生命週期
在傳統的Java應用中,Bean的生命週期非常簡單。 Java的關鍵詞new用來例項化Bean(或許他是非序列化的)。這樣就夠用了。 相反,Bean的生命週期在Spring容器中更加細緻。 理解Spring Bean的生命週期非常重要,因為你或許要利用Spring提供的機會來訂製Bean的建立過程。
bean生命週期
1.容器尋找Bean的定義資訊並且將其例項化。
2.受用依賴注入,Spring按照Bean定義資訊配置Bean的所有屬性。
3.如果Bean實現了BeanNameAware介面,工廠呼叫Bean的setBeanName()方法傳遞Bean的ID。
4.如果Bean實現了BeanFactoryAware介面,工廠呼叫setBeanFactory()方法傳入工廠自身。
5.如果BeanPostProcessor和Bean關聯,那麼它們的postProcessBeforeInitialzation()方法將被呼叫。
6.如果Bean指定了init-method方法,它將被呼叫。
7.最後,如果有BeanPsotProcessor和Bean關聯,那麼它們的postProcessAfterInitialization()方法將被呼叫。
到這個時候,Bean已經可以被應用系統使用了,並且將被保留在Bean Factory中知道它不再需要。
有兩種方法可以把它從Bean Factory中刪除掉。
1.如果Bean實現了DisposableBean介面,destory()方法被呼叫。
2.如果指定了訂製的銷燬方法,就呼叫這個方法。
Bean在Spring應用上下文的生命週期與在Bean工廠中的生命週期只有一點不同, 唯一不同的是,如果Bean實現了ApplicationContextAwre介面,setApplicationContext()方法被呼叫。
只有singleton行為的bean接受容器管理生命週期。
non-singleton行為的bean,Spring容器僅僅是new的替代,容器只負責建立。
對於singleton bean,Spring容器知道bean何時例項化結束,何時銷燬, Spring可以管理例項化結束之後,和銷燬之前的行為,管理bean的生命週期行為主要未如下兩個時機:
Bean全部依賴注入之後
Bean即將銷燬之前
1)依賴關係注入後的行為實現:
有兩種方法:A.編寫init方法 B.實現InitializingBean介面
afterPropertiesSet和init同時出現,前者先於後者執行,使用init方法,需要對配置檔案加入init-method屬性
2)bean銷燬之前的行為
有兩種方法:A.編寫close方法 B.實現DisposableBean介面
destroy和close同時出現,前者先於後者執行,使用close方法,需要對配置檔案加入destroy-method屬性
總體上分只為四個階段
1. BeanFactoyPostProcessor例項化
2. Bean例項化,然後通過某些BeanFactoyPostProcessor來進行依賴注入
3. BeanPostProcessor的呼叫.Spring內建的BeanPostProcessor負責呼叫Bean實現的介面: BeanNameAware, BeanFactoryAware, ApplicationContextAware等等,等這些內建的BeanPostProcessor呼叫完後才會呼叫自己配置的BeanPostProcessor
4.Bean銷燬階段
注:xml依賴注入中的bean.xml例子:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl">
</bean>
<bean id="userService" class="com.bjsxt.service.UserService">
<!--
<property name="userDAO" ref="u" />
-->
<constructor-arg>
<ref bean="u"/>
</constructor-arg>
</bean>
</beans></span>
五:Spring註解
1.準備工作
(1)匯入common-annotations.jar
(2)匯入schema檔案 檔名為spring-context-2.5.xsd
(3)在xml的beans節點中配置
2.xml配置工作
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
default-default-lazy-init="true">
<!--將針對註解的處理器配置好 -->
<context:annotation-config />
<!-- 使用annotation定義事務-->
<tx:annotation-driventransaction-managertx:annotation-driventransaction-manager="transactionManager" proxy-target-class="true"/>
<!--使用annotation 自動註冊bean,並檢查@Required,@Autowired的屬性已被注入base-package為需要掃描的包(含所有子包)-->
<context:component-scanbase-packagecontext:component-scanbase-package="com" />
.....
<beans>
注:<context:component-scan base-package="*.*" />
該配置隱式註冊了多個對註解進行解析的處理器,如:
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
RequiredAnnotationBeanPostProcessor
其實,註解本身做不了任何事情,和XML一樣,只起到配置的作用,主要在於背後強大的處理器,其中就包括了<context:annotation-config/>配置項裡面的註解所使用的處理器,所以配置了<context:component-scanbase-package="">之後,便無需再配置<context:annotation-config>
Autowired和resource
1.在java程式碼中使用@Autowired或@Resource註解方式進行裝配 ,這兩個註解的區別是:
@Autowired預設按型別裝配,
@Resource預設按名稱裝配,當找不到名稱匹配的bean才會按型別裝配。
@Autowired一般裝配在set方法之上,也可以裝配在屬性上邊,但是在屬性上邊配置,破壞了java的封裝,所以一般不建議使用。
@Autowired是根據型別進行自動裝配的。如果當Spring上下文中存在不止一個所要裝配型別的bean時,就會丟擲BeanCreationException異常;如果Spring上下文中不存在所要裝配型別的bean,也會丟擲BeanCreationException異常。
我們可以使用@Qualifier配合@Autowired來解決這些問題。
@Autowired
public void setUserDao(@Qualifier("userDao") UserDao userDao) {
this.userDao = userDao;
}
這樣,Spring會找到id為userDao的bean進行裝配。
可能不存在UserDao例項
@Autowired(required = false)
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
[email protected](JSR-250標準註解,推薦使用它來代替Spring專有的@Autowired註解)
Spring 不但支援自己定義的@Autowired註解,還支援幾個由JSR-250規範定義的註解,
它們分別是@Resource、@PostConstruct以及@PreDestroy。
@Resource的作用相當於@Autowired,只不過@Autowired按byType自動注入,而@Resource預設按byName自動注入罷了。
@Resource有兩個屬性是比較重要的,分別是name和type,Spring將@Resource註解的name屬性解析為bean的名字,而type屬性則解析為bean的型別。所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略
@Resource裝配順序
1 如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則丟擲異常
2