Spring的哲學是在不影響Java對象的設計的情況下將Java對象加入到框架中 我們下面來看看Spring的工作原理看看Spring是如何做到不影響Java對象的
EJB的框架采用了一種侵略性(Invasive)的方法來設計對象它要求你在設計中加入符合EJB規范的代碼一些輕量級的COP框架例如Avalon也要求對象設計時必須符合某種規范例如Serviceable接口這種做法是典型的Type 做法
這種設計思路要求Spring采用一種動態的靈活的方式來設計框架在Spring的工作原理中大量采用了反射首先Spring要解決的一個問題就是如何管理bean因為IOC的思想要求bean之間不能夠直接調用而應該采用一種被動的方式進行協作所以bean的管理是Spring工作原理中的核心部分
反射和內省在代碼的層次上思考問題有時候能夠帶來出人意料的靈活性但它的使用有時候也是一個哲學問題不論是在ORM設計還是在AOP設計上都出現了類似的問題究竟是使用反射還是使用代碼生成
在Spring中處理這個問題的核心是在orgspringframeworkbeans包中而其中最為核心的部分則是BeanWrapperBeanWrapper顧名思義就是bean的包裝器所以它的主要工作就是對任何一個bean進行屬性(包括內嵌屬性)的設置和方法的調用在
BeanWrapper的默認實現類BeanWrapperImpl中雖然代碼較長但完成的工作卻是非常的集中的
BeanWrapper的深入研究
我們看看這個BeanWrapper是如何發揮運作的假設我們有兩個bean
public class Company {
private String name;
private Employee managingDirector;
public String getName() {
return this
name;
}
public void setName(String name) {
this
name = name;
}
public Employee getManagingDirector() {
return this
managingDirector;
}
public void setManagingDirector(Employee managingDirector) {
this
managingDirector = managingDirector;
}
}
public class Employee {
private float salary;
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this
salary = salary;
}
}
然後我們使用BeanWrapper來調用這兩個bean
Company c = new Company();
BeanWrapper bwComp = BeanWrapperImpl(c);
// setting the company name
bwComp
setPropertyValue(
name
Some Company Inc
);
//
can also be done like this:
PropertyValue v = new PropertyValue(
name
Some Company Inc
);
bwComp
setPropertyValue(v);
// ok
lets create the director and tie it to the company:
Employee jim = new Employee();
BeanWrapper bwJim = BeanWrapperImpl(jim);
bwJim
setPropertyValue(
name
Jim Stravinsky
);
bwComp
setPropertyValue(
managingDirector
jim);
// retrieving the salary of the managingDirector through the company
Float salary = (Float)bwComp
getPropertyValue(
managingDirector
salary
);
看起來麻煩了許多但是這樣Spring就可以使用統一的方式來管理bean的屬性了
Bean的制造工廠
有了對單個Bean的包裝還需要對多個的bean進行管理在spring中把bean納入到一個核心庫中進行管理bean的生產有兩種方法一種是一個bean產生多個實例一種是一個bean只產生一個實例如果對設計模式熟悉的話我們就會想到前者可以采用Prototype後者可以采用Singleton
注意到反射技術的使用使得我們不再像原始的工廠方法模式那樣創建對象反射可以非常靈活的根據類的名稱創建一個對象所以spring只使用了Prototype和Singleton這兩個基本的模式
Spring正是這樣處理的但是我們希望用戶能夠維護統一的接口而不需要關心當前的bean到底是Prototype產生的獨立的bean還是Singleton產生的共享的bean所以在orgspringframeworkbeansfactory包中的BeanFactory定義了統一的getBean方法
JDBC再封裝JDBC優雅的封裝了底層的數據庫但是JDBC仍然存在諸多的不變你需要編寫大量的代碼來完成CRUD操作而且JDBC無論是遇到什麼樣的問題都拋出一個SQLException這種做法在異常使用上被稱為不完備的信息因為問題可能是很復雜的也許是數據庫連接的問題也許是並發控制的問題也許只是SQL語句出錯沒有理由用一個簡單的SQLException就搞定全部的問題了這種做法有些不負責任針對這兩個問題Spring Framework提出了兩種解決方法首先提供一個框架把JDBC應用中的獲取連接異常處理釋放等比較通用的操作全部都集中起來用戶只需要提供特定的實現就OK了實現的具體細節采用的是模板方法舉個例子在orgspringframeworkjdbcobject包中MappingSqlQuery類實現了將SQL查詢映射為具體的業務對象JavaDoc中這樣寫到Reusable query in which concrete subclasses must implement the abstract mapRow(ResultSet int) method to convert each row of the JDBC ResultSet into an object 用戶必須實現mapRow方法這是典型模板方法的應用我們拿一個具體的例子來看看
class UserQuery extends MappingSqlQuery {
public UserQuery(DataSource datasource) {
super(datasource
SELECT * FROM PUB_USER_ADDRESS WHERE USER_ID = ?
);
declareParameter(new SqlParameter(Types
NUMERIC));
compile();
}
// Map a result set row to a Java object
protected Object mapRow(ResultSet rs
int rownum) throws SQLException {
User user = new User();
user
setId(rs
getLong(
USER_ID
));
user
setForename(rs
getString(
FORENAME
));
return user;
}
public User findUser(long id) {
// Use superclass convenience method to provide strong typing
return (User) findObject(id);
}
}
其次是第二個問題最麻煩的地方應該說是需要截住JDBC的異常然後判斷異常的類型並重新拋出異常錯誤的問題可以通過連接來獲取所以麻煩的是如何截獲異常Spring 框架采用的方法是回調處理回調的類在Spring Framework中被稱為template
JdbcTemplate template = new JdbcTemplate(dataSource);
final List names = new LinkedList();
template
query(
SELECT USER
NAME FROM USER
new RowCallbackHandler() {
public void processRow(ResultSet rs) throws SQLException {
names
add(rs
getString(
));
}
});
回調函數是一個匿名類其中也使用了模板方法異常的處理都在父類中完成了
層間松耦合
在開放源碼界已經出現了大量的基於MVC的Web容器但是這些容器都僅限於Web的范圍 不涉及Web層次後端的連接Spring作為一個整體性的框架定義了一種Web層和後端業務層的連接方式 這個思路仍然疏運圖MVC的范疇但耦合更松散不依賴於具體的集成層次
public class GoogleSearchController
implements Controller {
private IGoogleSearchPort google;
private String googleKey;
public void setGoogle(IGoogleSearchPort google) {
this
google = google;
}
public void setGoogleKey(String googleKey) {
this
googleKey = googleKey;
}
public ModelAndView handleRequest(
HttpServletRequest request
HttpServletResponse response)
throws ServletException
IOException {
String query = request
getParameter(
query
);
GoogleSearchResult result =
// Google property definitions omitted
// Use google business object
google
doGoogleSearch(this
googleKey
query
start
maxResults
filter
r
estrict
safeSearch
lr
ie
oe);
return new ModelAndView(
googleResults
result
result);
}
}
回調函數是一個匿名類其中也使用了模板方法異常的處理都在父類中完成了
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28020.html