选择显示字体大小

品味spring的魅力


  spring的哲学是在不影响java对象的设计的情况下将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:

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 framework采用的方法是回调,处理回调的类在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(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, restrict, safesearch, lr, ie, oe);

   return new modelandview("googleresults", "result", result);
  }
 }

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


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons