Spring工做原理探秘

Spring的哲学是在不影响Java对象的设计的状况下将Java对象加入到框架中。  咱们下面来看看Spring的工做原理,看看Spring是如何作到不影响Java对象的。

EJB的框架采用了一种侵略性(Invasive)的方法来设计对象,它要求你在设计中加入符合EJB规范的代码。一些轻量级的COP框架,例如Avalon,也要求对象设计时必须符合某种规范,例如Serviceable接口,这种作法是典型的Type 1作法。

这 种设计思路要求Spring采用一种动态的、灵活的方式来设计框架。在Spring的工做原理中大量采用了反射。首先Spring要解决的一个问题就是如 何管理bean。由于IOC的思想要求bean之间不可以直接调用,而应该采用一种被动的方式进行协做。因此bean的管理是Spring工做原理中的核 心部分。

反射和内省在代码的层次上思考问题,有时候可以带来出人意料的灵活性。但它的使用有时候也是一个哲学问题,不管是在ORM设计仍是在AOP设计上都出现了相似的问题-到底是使用反射,仍是使用代码生成。

在 Spring中,处理这个问题的核心是在org.springframework.beans包中。而其中最为核心的部分,则是BeanWrapper。 BeanWrapper,顾名思义,就是bean的包装器。因此,它的主要工做,就是对任何一个bean,进行属性(包括内嵌属性)的设置和方法的调用。 在
BeanWrapper的默认实现类BeanWrapperImpl中,虽然代码较长,但完成的工做倒是很是的集中的。

BeanWrapper的深刻研究

咱们看看这个BeanWrapper是如何发挥运做的,假设咱们有两个bean:java

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。因此,在org.springframework.beans.factory包中的BeanFactory定
义了统一的getBean方法。 

JDBC再封装JDBC优雅的封装了底层的数据库,可是JDBC仍然存在诸多的不变。你须要编写大量的
代码来完成CRUD操做,并且,JDBC不管是遇到什么样的问题,都抛出一个SQLException,这种作法在异常使用上被称为不完备的信息。由于问
题多是很复杂的,也许是数据库链接的问题,也许是并发控制的问题,也许只是SQL语句出错。没有理由用一个简单的SQLException就搞定所有的
问题了,这种作法有些不负责任。针对这两个问题,Spring 
Framework提出了两种解决方法:首先,提供一个框架,把JDBC应用中的获取链接、异常处理、释放等比较通用的操做所有都集中起来,用户只须要提
供特定的实现就OK了。实现的具体细节采用的是模板方法。举个例子,在org.springframework.jdbc.object包
中,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 。spring

JdbcTemplate template = new JdbcTemplate(dataSource);   
final List names = new LinkedList();   
template.query("SELECT USER.NAME FROM USER",   
new RowCallbackHandler() {   
 public void proce***ow(ResultSet rs) throws SQLException {   
names.add(rs.getString(1));   
 }   
});

回调函数是一个匿名类,其中也使用了模板方法,异常的处理都在父类中完成了。

层间松耦合

在 开放源码界已经出现了大量的基于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);   
}   
 }

回调函数是一个匿名类,其中也使用了模板方法,异常的处理都在父类中完成了。
后端

相关文章
相关标签/搜索