java.lang.StackOverflowError错误

  今天,在运行wiring your web application with open source java时,当提交一份订单后,老是出现java.lang.StackOverflowError错误,经过调试,发现问题出在SaveOrderAction.java中,

里面有一段代码如下:

order.setOrderLineItems(lineItems);

__log.debug("the order before save is: "+ order.getUserName()+"this order is:"+order);

// delegate the save to the service layer and further upstream

Order returnedOrder = getOrderService().saveNewOrder(order);

__log.debug("the user's name who placed returnedOrder is: "+ returnedOrder.getUserName()+"this order is:"+returnedOrder);

oForm.setOrder(order);

request.setAttribute("form",oForm);

//ActionErrors errors = new ActionErrors();

//errors.add(Globals.ERROR_KEY, new ActionError("message.order.saved.successfully"));

//saveErrors(request, errors);

__log.debug("the order after set into form is: "+ order.getUserName()+"this order is:"+order);

return mapping.findForward("success");

  如果不注释掉上面3行,就会出现这个错误,真不知道是什么原因。报错信息如下:

“type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: Servlet execution threw an exception

root cause

java.lang.StackOverflowError

note The full stack trace of the root cause is available in the Apache Tomcat/5.0.25 logs.

  另外,如果把log4j配置成显示debug信息,控制台就会一直报告如下信息,不知是怎么一回事:

2006-01-06 22:40:21,564 DEBUG logicalcobwebs.proxool.spring:181  -> 000003 (00/01/00) - Connection #41 created to achieve minimum of 2 = AVAILABLE

2006-01-06 22:40:21,594 DEBUG logicalcobwebs.proxool.spring:181  -> 000003 (00/02/00) - Connection #42 created to achieve minimum of 2 = AVAILABLE

2006-01-06 22:40:51,618 DEBUG logicalcobwebs.proxool.spring:431  -> 000003 (00/01/00) - #0041 removed because it has problems: java.sql.SQLException: Syntax error or access violation,  message from server: "You have an error in your SQL syntax.  Check the manual that corresponds to your MySQL server version for the right syntax to use near 'values(current TimeStamp)' at line 1".

2006-01-06 22:40:51,628 DEBUG logicalcobwebs.proxool.spring:431  -> 000003 (00/00/00) - #0042 removed because it has problems: java.sql.SQLException: Syntax error or access violation,  message from server: "You have an error in your SQL syntax.  Check the manual that corresponds to your MySQL server version for the right syntax to use near 'values(current TimeStamp)' at line 1".

2006-01-06 22:40:51,638 DEBUG logicalcobwebs.proxool.spring:181  -> 000003 (00/01/00) - Connection #43 created to achieve minimum of 2 = AVAILABLE

2006-01-06 22:40:51,658 DEBUG logicalcobwebs.proxool.spring:181  -> 000003 (00/02/00) - Connection #44 created to achieve minimum of 2 = AVAILABLE

2006-01-06 22:41:00,661 INFO  proxool.stats.spring:66  -> 22:40:00 - 22:41:00, s:0:0.00/s, r:0:0.00/s, a:0.00ms/0.00

2006-01-06 22:41:21,671 DEBUG logicalcobwebs.proxool.spring:431  -> 000003 (00/01/00) - #0043 removed because it has problems: java.sql.SQLException: Syntax error or access violation,  message from server: "You have an error in your SQL syntax.  Check the manual that corresponds to your MySQL server version for the right syntax to use near 'values(current TimeStamp)' at line 1".

2006-01-06 22:41:21,681 DEBUG logicalcobwebs.proxool.spring:431  -> 000003 (00/00/00) - #0044 removed because it has problems: java.sql.SQLException: Syntax error or access violation,  message from server: "You have an error in your SQL syntax.  Check the manual that corresponds to your MySQL server version for the right syntax to use near 'values(current TimeStamp)' at line 1".

2006-01-06 22:41:21,711 DEBUG logicalcobwebs.proxool.spring:181  -> 000003 (00/01/00) - Connection #45 created to achieve minimum of 2 = AVAILABLE

2006-01-06 22:41:21,731 DEBUG logicalcobwebs.proxool.spring:181  -> 000003 (00/02/00) - Connection #46 created to achieve minimum of 2 = AVAILABLE

(java.sql.SQLException产生的原因是proxool.xml的配置问题:http://www.learndiary.com/disDiaryContentAction.do?goalID=1468)

我用的是tomcat5.0+mysql4.0.14

运行wiring your web application with...的问题

我用:struts1.1+spring1.2.6+hibernate2.1.8运行wiring your web application with open source java中碰到了如下问题:

  1)、必须遵照作者在源码readme.txt的安装使用说明,尤其是组件版本号,否则就会出问题。

     如:文中要求用 Hibernate 2.1.2,如果用hibernate2.1.8则会出现错误:HibernateException:Unable to locate config file:e:\\pro.xml。(见:HibernateException:Unable to locate config file:e:\\pro.xml (0篇) http://www.learndiary.com/disDiaryContentAction.do?searchDiaryID=1466&goalID=1466&naviStr=a10a2961)因为hibernate2.1.2支持绝对地址文件定位,而2.1.8是把这个文件放在classpath中寻找的,所以把源码中的:“applicationContext-hibernate.xml -

   - <prop key="hibernate.proxool.xml">C:/MyWSADProjects/OnJavaCom/WebContent/WEB-INF/proxool.xml</prop>”

  改为:“applicationContext-hibernate.xml -

   - <prop key="hibernate.proxool.xml">proxool.xml</prop>”

  再把“proxool.xml”放入WEB-INF/classes下面就行了;

  在build.xml文件中要求用:ant1.5.3,我用eclipse2.1下的ant1.5.2出错。

  还有就是源码中没有要求的用:xdolet如果是1.1的版本也不行,用最新的1.2.3解决问题;

  

  2)、把log4j.jar和common-logging.jar(这个文件是否必须这样没有验证)加入系统的classpath,否则会在编译build.xml时说找不到log4j的类。这好像也可以在build.xml文件中指定。

  3)、需要把build.xml中的下列内容改成你机器上的:

“ <property name="xdoclet.lib.home" value="c:/java_api/xdoclet-1.2/lib"/>

<property name="properties.dir"   value="." />

<property name="hibernate.lib.home" value="C:/java_api/hibernate-2.1/lib"/>

<property name="war.webinf.home" value="C:/MyWSADProjects/OnJavaCom/WebContent/WEB-INF"/>

<property name="mysql.lib.home" value="C:/java_api/mysql-connector-java-2.0.14"/>

<property name="db2.lib.home" value="C:/java_api/db2java"/>



   另外,如果你不用db2数据库,就把build.xml中关于db2的东西去掉。否则会出错。

  4)、数据库(mysql)需要先在数据库中把库建起再用build.xml脚本创建表。

  5)、怀疑是作者的笔误,在web.xml文件中的“<param-value>WEB-INF/struts-config.xml</param-value>”应该是“<param-value>WEB-INF/struts-config.xml</param-value>”,否则在我的tomcat5.0下就会报错,但是不知在其它容器中如何?

  6)、还有就是要把每个开源项目的包完整的拷到你的应用程序的lib中,比如:spring就要把它所有的在lib下的第三方支持包全部拷入你的应用程序的lib中。做这些事不要怕有冗余的文件,java的运行机制是要用的时候再去创建类的实例。多些文件只是占点硬盘空间而已。

  我觉得有必要好好的找一找这些错误出现的真正原因。

HibernateException:Unable to locate config file:e:\\pro.xml

在运行:wiring your web application with open source java时,如果不按照说明中的用hibernate2.1.2,比如:用2.1.8,就会出现文中的问题。

转帖:转自:http://spring.jactiongroup.net/viewtopic.php?t=940&highlight=.HibernateException%3A+Unable+to+locate+config+file

--------------------------------------------------------------------------------

 

软件环境:

struts+hibernate+spring

配置文件:

/WEB-INF/web.xml

引用:

..................

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

/WEB-INF/applicationContext-hibernate.xml

</param-value>

</context-param>

<servlet>

<servlet-name>SpringContextServlet</servlet-name>

<servlet-class>

org.springframework.web.context.ContextLoaderServlet

</servlet-class>

<load-on-startup>2</load-on-startup>

</servlet>

.............

 

/WEB-INF/applicationContext-hibernate.xml

引用:

<beans>

<!-- ========================= Start of PERSISTENCE DEFINITIONS ========================= -->

<!-- Choose the dialect that matches your "dataSource" definition -->

<bean id="mySessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">

<property name="mappingResources">

<list>

<value>com/hibernate/po/TbQueue.hbm.xml</value>

<value>com/hibernate/po/TMsgHistory.hbm.xml</value>

<value>com/hibernate/po/TbHistory.hbm.xml</value>

</list>

</property>

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">net.sf.hibernate.dialect.SQLServerDialect</prop>

<prop key="hibernate.show_sql">true</prop>

<prop key="connection.useUnicode">true</prop>

<prop key="connection.characterEncoding">GBK</prop>

<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>

<prop key="hibernate.proxool.xml">e:\\pro.xml</prop>

<prop key="hibernate.proxool.pool_alias">spring</prop>

</props>

</property>

</bean>

<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->

<bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">

<property name="sessionFactory"><ref local="mySessionFactory"/></property>

</bean>

<!-- Add more services here -->

<!-- CommonService-->

<bean id="commonService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

<property name="transactionManager"><ref local="myTransactionManager"/></property>

<property name="target"><ref local="commonServiceTarget"/></property>

<property name="transactionAttributes">

<props>

<prop key="find*">PROPAGATION_REQUIRED,readOnly,-DataAccessException</prop>

<prop key="save*">PROPAGATION_REQUIRED,-DataAccessException</prop>

<prop key="del*">PROPAGATION_REQUIRED,-DataAccessException</prop>

<prop key="update*">PROPAGATION_REQUIRED,-DataAccessException</prop>

<prop key="list*">PROPAGATION_REQUIRED,-DataAccessException</prop>

</props>

</property>

</bean>

<bean id="commonServiceTarget" class="org.common.spring.CommonServiceImpl">

<property name="hibernateDAO"><ref local="hibernateDAO"/></property>

</bean>

<!-- DAO定义区 -->

<bean id="hibernateDAO" class="org.common.hibernate.HibernateDAOImpl">

<property name="sessionFactory"><ref local="mySessionFactory"/></property>

</bean>

</beans>

 

e:\pro.xml

引用:

<proxool>

<alias>spring</alias>

<driver-url>jdbc:jtds:sqlserver://127.0.0.1/test;TDS=8.0</driver-url>

<driver-class>net.sourceforge.jtds.jdbc.Driver</driver-class>

<driver-properties>

<property name="user" value="sa" />

<property name="password" value="" />

</driver-properties>

<minimum-connection-count>2</minimum-connection-count>

<maximum-connection-count>20</maximum-connection-count>

<maximum-connection-lifetime>18000000</maximum-connection-lifetime> <!-- 5 hours -->

<house-keeping-test-sql>values(current TimeStamp)</house-keeping-test-sql>

<statistics>1m,15m,1d</statistics>

<statistics-log-level>INFO</statistics-log-level>

<fatal-sql-exception>Connection is closed,SQLSTATE=08003,Error opening socket. SQLSTATE=08S01,SQLSTATE=08S01</fatal-sql-exception>

<fatal-sql-exception-wrapper-class>org.logicalcobwebs.proxool.FatalRuntimeException</fatal-sql-exception-wrapper-class>

<verbose>false</verbose>

</proxool>

 

BaseAction.java

引用:

public abstract class BaseAction extends org.apache.struts.action.Action {

private CommonService commonService;

public void setServlet(ActionServlet actionServlet) {

super.setServlet(actionServlet);

ServletContext servletContext = actionServlet.getServletContext();

WebApplicationContext wac = WebApplicationContextUtils

.getRequiredWebApplicationContext(servletContext);

this.commonService=(CommonService)wac.getBean("commonService");

}

public CommonService getCommonService() {

return commonService;

}

}

 

在服务器启动时报错,信息如下:

引用:

信息: Installing web application at context path /phoneMsg from URL file:F:\tomcat\webapps\phoneMsg

2004-10-26 18:29:19,750 FATAL net.sf.hibernate.util.ConfigHelper - Unable to locate config file: e:\\pro.xml

2004-10-26 18:29:19,781 ERROR org.springframework.web.context.ContextLoader - Context initialization failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mySessionFactory' defined in resource [/WEB-INF/applicationContext-hibernate.xml] of ServletContext: Initialization of bean failed; nested exception is net.sf.hibernate.HibernateException: Unable to locate config file: e:\\pro.xml

net.sf.hibernate.HibernateException: Unable to locate config file: e:\\pro.xml

at net.sf.hibernate.util.ConfigHelper.getConfigStream(ConfigHelper.java:83)

at net.sf.hibernate.util.ConfigHelper.getConfigStreamReader(ConfigHelper.java:104)

at net.sf.hibernate.connection.ProxoolConnectionProvider.configure(ProxoolConnectionProvider.java:122)

at net.sf.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:83)

at net.sf.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:65)

at net.sf.hibernate.cfg.Configuration.buildSettings(Configuration.java:1155)

 

pro.xml的确在E盘啊???

 

返回页首      

 

 

chinalyc

spring 爱好者

注册时间: 2004-02-16

帖子: 6

来自: 北京

 发表于: Fri Nov 05, 2004 9:45 am    发表主题:   

--------------------------------------------------------------------------------

 

在net.sf.hibernate.util.ConfigHelper类中它是这样取先取一个文件的url。

代码:

final URL url = ConfigHelper.locateConfig(path);

public static final URL locateConfig(final String path) {

      try {

         return new URL(path);

      }

      catch(MalformedURLException e) {

                                               

         return findAsResource(path);

      }

   }

   public static final URL findAsResource(final String path) {

      URL url = null;

      // First, try to locate this resource through the current

      // context classloader.

      url = Thread.currentThread().getContextClassLoader().getResource(path);

      if (url != null)

         return url;

      // Next, try to locate this resource through this class's classloader

      url = ConfigHelper.class.getClassLoader().getResource(path);

      if (url != null)

         return url;

      // Next, try to locate this resource through the system classloader

      url = ClassLoader.getSystemClassLoader().getResource(path);

      // Anywhere else we should look?

      return url;

   }

你还是把这个文件放在classes目录吧

 

 

结合重译wiring web application with open source java学习Spring...

  学习其中的内容。

  totodo在2004年9月就已经翻译了这篇文章,总体还可以。我准备重译的同时学习文中的用Struts+Spring+Hibernate构建web应用。今天下载了文中的源码。

  我觉得当前在完善学习日记用户界面和重译这篇文章这两件事之间,重译和学习这篇文章应该优先。

(转帖)POJO 与 PO的 概念

转自:http://www.kissjava.com/zhuanti/hibernate/2005-06-03/13341117764046.html

[文章信息]

 

作者: robbin

时间: 2005-06-03 13:29:44

出处: KissJava.com

责任编辑: Icy

点击: 

 

[文章导读]

 

POJO 与 PO的 概念

 

 

 

  

专题推荐

 · 手机游戏开发专辑

· Struts专题学习

· Hibernate大杂烩

· WebWork全接触

· Spring - 春的诱惑

· Eclipse使用大全

· JBuilder 开发者指南

· Ant - 让编程更轻松

 

 

 

热门文章

 ·  图解利用Eclipse3+Lomboz3+Tomcat开发JSP(4673)

·  图解利用Eclipse3+Lomboz3+Tomcat开发JSP(4673)

·  史上最简单的struts+spring+hibernate配置实例(4657)

·  Eclipse 平台Java开发入门(4568)

·  Eclipse 平台Java开发入门(4568)

·  Spring 入门(一个简单的例子)(3349)

·  J2SDK和TOMCAT的安装及配置(2680)

·  struts傻瓜式学习(一天篇)(2572)

·  Spring framework 10分钟入门(2188)

·  图解利用Eclipse3+Lomboz3+Tomcat开发JSP(1704)

 

 

 

 

 

[正文]

 

 

 

 

   POJO = pure old java object or plain ordinary java object or what ever.

PO = persisent object 持久对象

就是说在一些Object/Relation Mapping工具中,能够做到维护数据库表记录的persisent object完全是一个符合Java Bean规范的纯Java对象,没有增加别的属性和方法。全都是这样子的:

public class User {

  private long id;

  private String name;

  public void setId(long id) {

 this.id = id;



public void setName(String name) {

this.name=name;

}

 public long getId() {

 return id;



public String getName() {

return name;

}

--------------------------------------------------------------------------------

首先要区别持久对象和POJO。

持久对象实际上必须对应数据库中的entity,所以和POJO有所区别。比如说POJO是由new创建,由GC回收。但是持久对象是insert数据库创建,由数据库delete删除的。基本上持久对象生命周期和数据库密切相关。另外持久对象往往只能存在一个数据库Connection之中,Connnection关闭以后,持久对象就不存在了,而POJO只要不被GC回收,总是存在的。

由于存在诸多差别,因此持久对象PO(Persistent Object)在代码上肯定和POJO不同,起码PO相对于POJO会增加一些用来管理数据库entity状态的属性和方法。而ORM追求的目标就是要PO在使用上尽量和POJO一致,对于程序员来说,他们可以把PO当做POJO来用,而感觉不到PO的存在。

JDO的实现方法是这样的:

1、编写POJO

2、编译POJO

3、使用JDO的一个专门工具,叫做Enhancer,一般是一个命令行程序,手工运行,或者在ant脚本里面运行,对POJO的class文件处理一下,把POJO替换成同名的PO。

4、在运行期运行的实际上是PO,而不是POJO。

该方法有点类似于JSP,JSP也是在编译期被转换成Servlet来运行的,在运行期实际上运行的是Servlet,而不是JSP。

Hibernate的实现方法比较先进:

1、编写POJO

2、编译POJO

3、直接运行,在运行期,由Hibernate的CGLIB动态把POJO转换为PO。

由此可以看出Hibernate是在运行期把POJO的字节码转换为PO的,而JDO是在编译期转换的。一般认为JDO的方式效率会稍高,毕竟是编译期转换嘛。但是Hibernate的作者Gavin King说CGLIB的效率非常之高,运行期的PO的字节码生成速度非常之快,效率损失几乎可以忽略不计。

实际上运行期生成PO的好处非常大,这样对于程序员来说,是无法接触到PO的,PO对他们来说完全透明。可以更加自由的以POJO的概念操纵PO。另外由于是运行期生成PO,所以可以支持增量编译,增量调试。而JDO则无法做到这一点。实际上已经有很多人在抱怨JDO的编译期Enhancer问题了,而据说JBossDO将采用运行期生成PO字节码,而不采用编译期生成PO字节码。

另外一个相关的问题是,不同的JDO产品的Enhancer生成的PO字节码可能会有所不同,可能会影响在JDO产品之间的可移植性,这一点有点类似EJB的可移植性难题。

--------------------------------------------------------------------------------

由这个问题另外引出一个JDO的缺陷。

由于JDO的PO状态管理方式,所以当你在程序里面get/set的时候,实际上不是从PO的实例中取values,而是从JDO ?中取出来,所以一旦PM关闭,PO就不能进行存取了。

在JDO中,也可以通过一些办法使得PO可以在PM外面使用,比如说定义PO是transient的,但是该PO在PM关闭后就没有PO identity了。无法进行跨PM的状态管理。

而Hibernate是从PO实例中取values的,所以即使Session关闭,也一样可以get/set,可以进行跨Session的状态管理。

在分多层的应用中,由于持久层和业务层和web层都是分开的,此时Hibernate的PO完全可以当做一个POJO来用,也就是当做一个VO,在各层间自由传递,而不用去管Session是开还是关。如果你把这个POJO序列化的话,甚至可以用在分布式环境中。(不适合lazy loading的情况)

但是JDO的PO在PM关闭后就不能再用了,所以必须在PM关闭前把PO拷贝一份VO,把VO传递给业务层和web层使用。在非分布式环境中,也可以使用ThreadLocal模式确保PM始终是打开状态,来避免每次必须进行PO到VO的拷贝操作。但是不管怎么说,这总是权宜之计,不如Hibernate的功能强。

Inversion of Control Containers and the Dependency Injection

这篇文章看来也不错,还有中文的译文的pdf文档。贴在这里,以后慢慢看。

(转自:http://martinfowler.com/articles/injection.html)

 Home Blog Articles Books About Me Contact Me ThoughtWorks

Inversion of Control Containers and the Dependency Injection pattern

Martin Fowler

In the Java community there's been a rush of lightweight containers that help to assemble components from different projects into a cohesive application. Underlying these containers is a common pattern to how they perform the wiring, a concept they refer under the very generic name of "Inversion of Control". In this article I dig into how this pattern works, under the more specific name of "Dependency Injection", and contrast it with the Service Locator alternative. The choice between them is less important than the principle of separating configuration from use.

Last significant update: 23 Jan 04

| Chinese | Portuguese | French |

Contents

Components and Services

A Naive Example

Inversion of Control

Forms of Dependency Injection

Constructor Injection with PicoContainer

Setter Injection with Spring

Interface Injection

Using a Service Locator

Using a Segregated Interface for the Locator

A Dynamic Service Locator

Using both a locator and injection with Avalon

Deciding which option to use

Service Locator vs Dependency Injection

Constructor versus Setter Injection

Code or configuration files

Separating Configuration from Use

Some further issues

Concluding Thoughts

--------------------------------------------------------------------------------

One of the entertaining things about the enterprise Java world is the huge amount of activity in building alternatives to the mainstream J2EE technologies, much of it happening in open source. A lot of this is a reaction to the heavyweight complexity in the mainstream J2EE world, but much of it is also exploring alternatives and coming up with creative ideas. A common issue to deal with is how to wire together different elements: how do you fit together this web controller architecture with that database interface backing when they were built by different teams with little knowledge of each other.A number of frameworks have taken a stab at this problem, and several are branching out to provide a general capability to assemble components from different layers. These are often referred to as lightweight containers, examples include PicoContainer, and Spring.

Underlying these containers are a number of interesting design principles, things that go beyond both these specific containers and indeed the Java platform. Here I want to start exploring some of these principles. The examples I use are in Java, but like most of my writing the principles are equally applicable to other OO environments, particularly .NET.

--------------------------------------------------------------------------------

Components and Services

The topic of wiring elements together drags me almost immediately into the knotty terminology problems that surround the terms service and component. You find long and contradictory articles on the definition of these things with ease. For my purposes here are my current uses of these overloaded terms.

I use component to mean a glob of software that's intended to be used, without change, by application that is out of the control of the writers of the component. By 'without change' I mean that the using application doesn't change the source code of the components, although they may alter the component's behavior by extending it in ways allowed by the component writers.

A service is similar to a component in that it's used by foreign applications. The main difference is that I expect a component to be used locally (think jar file, assembly, dll, or a source import). A service will be used remotely through some remote interface, either synchronous or asynchronous (eg web service, messaging system, RPC, or socket.)

I mostly use service in this article, but much of the same logic can be applied to local components too. Indeed often you need some kind of local component framework to easily access a remote service. But writing "component or service" is tiring to read and write, and services are much more fashionable at the moment.

--------------------------------------------------------------------------------

A Naive Example

To help make all of this more concrete I'll use a running example to talk about all of this. Like all of my examples it's one of those super-simple examples; small enough to be unreal, but hopefully enough for you to visualize what's going on without falling into the bog of a real example.

In this example I'm writing a component that provides a list of movies directed by a particular director. This stunningly useful function is implemented by a single method.

class MovieLister...

    public Movie[] moviesDirectedBy(String arg) {

        List allMovies = finder.findAll();

        for (Iterator it = allMovies.iterator(); it.hasNext();) {

            Movie movie = (Movie) it.next();

            if (!movie.getDirector().equals(arg)) it.remove();

        }

        return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);

    }

The implementation of this function is naive in the extreme, it asks a finder object (which we'll get to in a moment) to return every film it knows about. Then it just hunts through this list to return those directed by a particular director. This particular piece of naivety I'm not going to fix, since it's just the scaffolding for the real point of this article.

The real point of this article is this finder object, or particularly how we connect the lister object with a particular finder object. The reason why this is interesting is that I want my wonderful moviesDirectedBy method to be completely independent of how all the movies are being stored. So all the method does is refer to a finder, and all that finder does is know how to respond to the findAll method. I can bring this out by defining an interface for the finder.

public interface MovieFinder {

    List findAll();

}

Now all of this is very well decoupled, but at some point I have to come up with a concrete class to actually come up with the movies. In this case I put the code for this in the constructor of my lister class.

class MovieLister...

  private MovieFinder finder;

  public MovieLister() {

    finder = new ColonDelimitedMovieFinder("movies1.txt");

  }

The name of the implementation class comes from the fact that I'm getting my list from a colon delimited text file. I'll spare you the details, after all the point is just that there's some implementation.

Now if I'm using this class for just myself, this is all fine and dandy. But what happens when my friends are overwhelmed by a desire for this wonderful functionality and would like a copy of my program? If they also store their movie listings in a colon delimited text file called "movies1.txt" then everything is wonderful. If they have a different name for their movies file, then it's easy to put the name of the file in a properties file. But what if they have a completely different form of storing their movie listing: a SQL database, an XML file, a web service, or just another format of text file? In this case we need a different class to grab that data. Now because I've defined a MovieFinder interface, this won't alter my moviesDirectedBy method. But I still need to have some way to get an instance of the right finder implementation into place.

Figure 3: The dependencies using a simple creation in the lister class

Figure 3 shows the dependencies for this situation. The MovieLister class is dependent on both the MovieFinder interface and upon the implementation. We would prefer it if it were only dependent on the interface, but then how do we make an instance to work with?

In my book P of EAA, we described this situation as a Plugin. The implementation class for the finder isn't linked into the program at compile time, since I don't know what my friends are going to use. Instead we want my lister to work with any implementation, and for that implementation to be plugged in at some later point, out of my hands. The problem is how can I make that link so that my lister class is ignorant of the implementation class, but can still talk to an instance to do its work.

Expanding this into a real system, we might have dozens of such services and components. In each case we can abstract our use of these components by talking to them through an interface (and using an adapter if the component isn't designed with an interface in mind). But if we wish to deploy this system in different ways, we need to use plugins to handle the interaction with these services so we can use different implementations in different deployments.

So the core problem is how do we assemble these plugins into an application? This is one of the main problems that this new breed of lightweight containers face, and universally they all do it using Inversion of Control.

--------------------------------------------------------------------------------

Inversion of Control

When these containers talk about how they are so useful because they implement "Inversion of Control" I end up very puzzled. Inversion of control is a common characteristic of frameworks, so saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels.

The question, is what aspect of control are they inverting? When I first ran into inversion of control, it was in the main control of a user interface. Early user interfaces were controlled by the application program. You would have a sequence of commands like "Enter name", "enter address"; your program would drive the prompts and pick up a response to each one. With graphical (or even screen based) UIs the UI framework would contain this main loop and your program instead provided event handlers for the various fields on the screen. The main control of the program was inverted, moved away from you to the framework.

For this new breed of containers the inversion is about how they lookup a plugin implementation. In my naive example the lister looked up the finder implementation by directly instantiating it. This stops the finder from being a plugin. The approach that these containers use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the lister.

As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.

I'm going to start by talking about the various forms of dependency injection, but I'll point out now that that's not the only way of removing the dependency from the application class to the plugin implementation. The other pattern you can use to do this is Service Locator, and I'll discuss that after I'm done with explaining Dependency Injection.

--------------------------------------------------------------------------------

Forms of Dependency Injection

The basic idea of the Dependency Injection is to have a separate object, an assembler, that populates a field in the lister class with an appropriate implementation for the finder interface, resulting in a dependency diagram along the lines of Figure 1

Figure 1: The dependencies for a Dependency Injector

There are three main styles of dependency injection. The names I'm using for them are Constructor Injection, Setter Injection, and Interface Injection. If you read about this stuff in the current discussions about Inversion of Control you'll hear these referred to as type 1 IoC (interface injection), type 2 IoC (setter injection) and type 3 IoC (constructor injection). I find numeric names rather hard to remember, which is why I've used the names I have here.

Constructor Injection with PicoContainer

I'll start with showing how this injection is done using a lightweight container called PicoContainer. I'm starting here primarily because several of my colleagues at ThoughtWorks are very active in the development of PicoContainer (yes, it's a sort of corporate nepotism.)

PicoContainer uses a constructor to decide how to inject a finder implementation into the lister class. For this to work, the movie lister class needs to declare a constructor that includes everything it needs injected.

class MovieLister...

    public MovieLister(MovieFinder finder) {

        this.finder = finder;      

    }

The finder itself will also be managed by the pico container, and as such will have the filename of the text file injected into it by the container.

class ColonMovieFinder...

    public ColonMovieFinder(String filename) {

        this.filename = filename;

    }

The pico container then needs to be told which implementation class to associate with each interface, and which string to inject into the finder.

    private MutablePicoContainer configureContainer() {

        MutablePicoContainer pico = new DefaultPicoContainer();

        Parameter[] finderParams =  {new ConstantParameter("movies1.txt")};

        pico.registerComponentImplementation(MovieFinder.class, ColonMovieFinder.class, finderParams);

        pico.registerComponentImplementation(MovieLister.class);

        return pico;

    }

This configuration code is typically set up in a different class. For our example, each friend who uses my lister might write the appropriate configuration code in some setup class of their own. Of course it's common to hold this kind of configuration information in separate config files. You can write a class to read a config file and set up the container appropriately. Although PicoContainer doesn't contain this functionality itself, there is a closely related project called NanoContainer that provides the appropriate wrappers to allow you to have XML configuration files. Such a nano container will parse the XML and then configure an underlying pico container. The philosophy of the project is to separate the config file format from the underlying mechanism.

To use the container you write code something like this.

    public void testWithPico() {

        MutablePicoContainer pico = configureContainer();

        MovieLister lister = (MovieLister) pico.getComponentInstance(MovieLister.class);

        Movie[] movies = lister.moviesDirectedBy("Sergio Leone");

        assertEquals("Once Upon a Time in the West", movies[0].getTitle());

    }

Although in this example I've used constructor injection, PicoContainer also supports setter injection, although it's developers do prefer constructor injection.

Setter Injection with Spring

The Spring framework is a wide ranging framework for enterprise Java development. It includes abstraction layers for transactions, persistence frameworks, web application development and JDBC. Like PicoContainer it supports both constructor and setter injection, but its developers tend to prefer setter injection - which makes it an appropriate choice for this example.

To get my movie lister to accept the injection I define a setting method for that service

class MovieLister...

    private MovieFinder finder;

  public void setFinder(MovieFinder finder) {

    this.finder = finder;

  }

Similarly I define a setter for the string the finder.

class ColonMovieFinder...

    public void setFilename(String filename) {

        this.filename = filename;

    }

The third step is to set up the configuration for the files. Spring supports configuration through XML files and also through code, but XML is the expected way to do it.

    <beans>

        <bean id="MovieLister" class="spring.MovieLister">

            <property name="finder">

                <ref local="MovieFinder"/>

            </property>

        </bean>

        <bean id="MovieFinder" class="spring.ColonMovieFinder">

            <property name="filename">

                <value>movies1.txt</value>

            </property>

        </bean>

    </beans>

The test then looks like this.

    public void testWithSpring() throws Exception {

        ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");

        MovieLister lister = (MovieLister) ctx.getBean("MovieLister");

        Movie[] movies = lister.moviesDirectedBy("Sergio Leone");

        assertEquals("Once Upon a Time in the West", movies[0].getTitle());

    }

Interface Injection

The third injection technique is to define and use interfaces for the injection. Avalon is an example of a framework that uses this technique in places. I'll talk a bit more about that later, but in this case I'm going to use it with some simple sample code.

With this technique I begin by defining an interface that I'll use to perform the injection through. Here's the interface for injecting a movie finder into an object.

public interface InjectFinder {

    void injectFinder(MovieFinder finder);

}

This interface would be defined by whoever provides the MovieFinder interface. It needs to be implemented by any class that wants to use a finder, such as the lister.

class MovieLister implements InjectFinder...

    public void injectFinder(MovieFinder finder) {

        this.finder = finder;

    }

I use a similar approach to inject the filename into the finder implementation.

public interface InjectFinderFilename {

    void injectFilename (String filename);

}

class ColonMovieFinder implements MovieFinder, InjectFinderFilename......

    public void injectFilename(String filename) {

        this.filename = filename;

    }

Then, as usual, I need some configuration code to wire up the implementations. For simplicity's sake I'll do it in code.

class Tester...

    private Container container;

     private void configureContainer() {

       container = new Container();

       registerComponents();

       registerInjectors();

       container.start();

    }

This configuration has two stages, registering components through lookup keys is pretty similar to the other examples.

class Tester...

  private void registerComponents() {

    container.registerComponent("MovieLister", MovieLister.class);

    container.registerComponent("MovieFinder", ColonMovieFinder.class);

  }

A new step is to register the injectors that will inject the dependent components. Each injection interface needs some code to inject the dependent object. Here I do this by registering injector objects with the container. Each injector object implements the injector interface.

class Tester...

  private void registerInjectors() {

    container.registerInjector(InjectFinder.class, container.lookup("MovieFinder"));

    container.registerInjector(InjectFinderFilename.class, new FinderFilenameInjector());

  }

public interface Injector {

  public void inject(Object target);

}

When the dependent is a class written for this container, it makes sense for the component to implement the injector interface itself, as I do here with the movie finder. For generic classes, such as the string, I use an inner class within the configuration code.

class ColonMovieFinder implements Injector......

  public void inject(Object target) {

    ((InjectFinder) target).injectFinder(this);       

  }

class Tester...

  public static class FinderFilenameInjector implements Injector {

    public void inject(Object target) {

      ((InjectFinderFilename)target).injectFilename("movies1.txt");     

    }

    }

The tests then use the container.

class IfaceTester...

    public void testIface() {

      configureContainer();

      MovieLister lister = (MovieLister)container.lookup("MovieLister");

      Movie[] movies = lister.moviesDirectedBy("Sergio Leone");

      assertEquals("Once Upon a Time in the West", movies[0].getTitle());

    }

The container uses the declared injection interfaces to figure out the dependendencies and the injectors to inject the correct dependents. (The specific container implementation I did here isn't important to the technique, and I won't show it because you'd only laugh.)

--------------------------------------------------------------------------------

Using a Service Locator

The key benefit of a Dependency Injector is that it removes the dependency that the MovieLister class has on the concrete MovieFinder implementation. This allows me to give listers to friends and for them to plug in a suitable implementation for their own environment. Injection isn't the only way to break this dependency, another is to use a service locator.

The basic idea behind a service locator is to have an object that knows how to get hold of all of the services that an application might need. So a service locator for this application would have a method that returns a movie finder when one is needed. Of course this just shifts the burden a tad, we still have to get the locator into the lister, resulting in the dependencies of Figure 2

Figure 2: The dependencies for a Service Locator

In this case I'll use the ServiceLocator as a singleton Registry. The lister can then use that to get the finder when it's instantiated.

class MovieLister...

    MovieFinder finder = ServiceLocator.movieFinder();

class ServiceLocator...

    public static MovieFinder movieFinder() {

        return soleInstance.movieFinder;

    }

    private static ServiceLocator soleInstance;

    private MovieFinder movieFinder;

As with the injection approach, we have to configure the service locator. Here I'm doing it in code, but it's not hard to use a mechanism that would read the appropriate data from a configuration file.

class Tester...

    private void configure() {

        ServiceLocator.load(new ServiceLocator(new ColonMovieFinder("movies1.txt")));

    }

class ServiceLocator...

    public static void load(ServiceLocator arg) {

        soleInstance = arg;

    }

    public ServiceLocator(MovieFinder movieFinder) {

        this.movieFinder = movieFinder;

    }

Here's the test code.

class Tester...

    public void testSimple() {

        configure();

        MovieLister lister = new MovieLister();

        Movie[] movies = lister.moviesDirectedBy("Sergio Leone");

        assertEquals("Once Upon a Time in the West", movies[0].getTitle());

    }

I've often heard the complaint that these kinds of service locators are a bad thing because they aren't testable because you can't substitute implementations for them. Certainly you can design them badly to get into this kind of trouble, but you don't have to. In this case the service locator instance is just a simple data holder. I can easily create the locator with test implementations of my services.

For a more sophisticated locator I can subclass service locator and pass that subclass into the registry's class variable. I can change the static methods to call a method on the instance rather accessing instance variables directly. I can provide thread specific locators by using thread specific storage. All of this can be done without changing clients of service locator.

A way to think of this is that service locator is a registry not a singleton. A singleton provides a simple way of implementing a registry, but that implementation decision is easily changed.

Using a Segregated Interface for the Locator

One of the issues with the simple approach above, is that the MovieLister is dependent on the full service locator class, even though it only uses one service. We can reduce this by using a segregated interface. That way, instead of using the full service locator interface, the lister can declare just the bit of interface it needs.

In this situation the provider of the lister would also provide a locator interface which it needs to get hold of the finder.

public interface MovieFinderLocator {

    public MovieFinder movieFinder();

The locator then needs to implement this interface to provide access to a finder.

    MovieFinderLocator locator = ServiceLocator.locator();

    MovieFinder finder = locator.movieFinder();

   public static ServiceLocator locator() {

        return soleInstance;

    }

    public MovieFinder movieFinder() {

        return movieFinder;

    }

    private static ServiceLocator soleInstance;

    private MovieFinder movieFinder;

You'll notice that since we want to use an interface, we can't just access the services through static methods any more. We have to use the class to get a locator instance and then use that to get what we need.

A Dynamic Service Locator

The above example was static, in that the service locator class has methods for each of the services that you need. This isn't the only way of doing it, you can also make a dynamic service locator that allows you to stash any service you need into it and make your choices at runtime.

In this case, the service locator uses a map instead of fields for each of the services, and provides generic methods to get and load services.

class ServiceLocator...

    private static ServiceLocator soleInstance;

    public static void load(ServiceLocator arg) {

        soleInstance = arg;

    }

    private Map services = new HashMap();

    public static Object getService(String key){

        return soleInstance.services.get(key);

    }

    public void loadService (String key, Object service) {

        services.put(key, service);

    }

Configuring involves loading a service with an appropriate key.

class Tester...

    private void configure() {

        ServiceLocator locator = new ServiceLocator();

        locator.loadService("MovieFinder", new ColonMovieFinder("movies1.txt"));

        ServiceLocator.load(locator);

    }

I use the service by using the same key string.

class MovieLister...

    MovieFinder finder = (MovieFinder) ServiceLocator.getService("MovieFinder");

On the whole I dislike this approach. Although it's certainly flexible, it's not very explicit. The only way I can find out how to reach a service is through textual keys. I prefer explicit methods because it's easier to find where they are by looking at the interface definitions.

Using both a locator and injection with Avalon

Dependency injection and a service locator aren't necessarily mutually exclusive concepts. A good example of using both together is the Avalon framework. Avalon uses a service locator, but uses injection to tell components where to find the locator.

Berin Loritsch sent me this simple version of my running example using Avalon.

public class MyMovieLister implements MovieLister, Serviceable {

    private MovieFinder finder;

    public void service( ServiceManager manager ) throws ServiceException {

        finder = (MovieFinder)manager.lookup("finder");

    }

     

The service method is an example of interface injection, allowing the container to inject a service manager into MyMovieLister. The service manager is an example of a service locator. In this example the lister doesn't store the manager in a field, instead it immediately uses it to lookup the finder, which it does store.

--------------------------------------------------------------------------------

Deciding which option to use

So far I've concentrated on explaining how I see these patterns and their variations. Now I can start talking about their pros and cons to help figure out which ones to use and when.

Service Locator vs Dependency Injection

The fundamental choice is between Service Locator and Dependency Injection. The first point is that both implementations provide the fundamental decoupling that's missing in the naive example - in both cases application code is independent of the concrete implementation of the service interface. The important difference between the two patterns is about how that implementation is provided to the application class. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control.

Inversion of control is a common feature of frameworks, but it's something that comes at a price. It tends to be hard to understand and leads to problems when you are trying to debug. So on the whole I prefer to avoid it unless I need it. This isn't to say it's a bad thing, just that I think it needs to justify itself over the more straightforward alternative.

The key difference is that with a Service Locator every user of a service has a dependency to the locator. The locator can hide dependencies to other implementations, but you do need to see the locator. So the decision between locator and injector depends on whether that dependency is a problem.

Using dependency injection can help make it easier to see what the component dependencies are. With dependency injector you can just look at the injection mechanism, such as the constructor, and see the dependencies. With the service locator you have to search the source code for calls to the locator. Modern IDEs with a find references feature make this easier, but it's still not as easy as looking at the constructor or setting methods.

A lot of this depends on the nature of the user of the service. If you are building an application with various classes that use a service, then a dependency from the application classes to the locator isn't a big deal. In my example of giving a Movie Lister to my friends, then using a service locator works quite well. All they need to do is to configure the locator to hook in the right service implementations, either through some configuration code or through a configuration file. In this kind of scenario I don't see the injector's inversion as providing anything compelling.

The difference comes if the lister is a component that I'm providing to an application that other people are writing. In this case I don't know much about the APIs of the service locators that my customers are going to use. Each customer might have their own incompatible service locators. I can get around around some of this by using the segregated interface. Each customer can write an adapter that matches my interface to their locator, but in any case I still need to see the first locator to lookup my specific interface. And once the adapter appears then the simplicity of the direct connection to a locator is beginning to slip.

Since with an injector you don't have a dependency from a component to the injector, the component cannot obtain further services from the injector once it's been configured.

A common reason people give for preferring dependency injection is that it makes testing easier. The point here is that to do testing, you need to easily replace real service implementations with stubs or mocks. However there is really no difference here between dependency injection and service locator: both are very amenable to stubbing. I suspect this observation comes from projects where people don't make the effort to ensure that their service locator can be easily substituted. This is where continual testing helps, if you can't easily stub services for testing, then this implies a serious problem with your design.

Of course the testing problem is exacerbated by component environments that are very intrusive, such as Java's EJB framework. My view is that these kinds of frameworks should minimize their impact upon application code, and particularly should not do things that slow down the edit-execute cycle. Using plugins to substitute heavyweight components does a lot help this process, which is vital for practices such as Test Driven Development.

So the primary issue is for people who are writing code that expects to be used in applications outside of the control of the writer. In these cases even a minimal assumption about a Service Locator is a problem.

Constructor versus Setter Injection

For service combination, you always have to have some convention in order to wire things together. The advantage of injection is primarily that it requires very simple conventions - at least for the constructor and setter injections. You don't have to do anything odd in your component and it's fairly straightforward for an injector to get everything configured.

Interface injection is more invasive since you have to write a lot of interfaces to get things all sorted out. For a small set of interfaces required by the container, such as in Avalon's approach, this isn't too bad. But it's a lot of work for assembling components and dependencies, which is why the current crop of lightweight containers go with setter and constructor injection.

The choice between setter and constructor injection is interesting as it mirrors a more general issue with object-oriented programming - should you fill fields in a constructor or with setters.

My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations.

Another advantage with constructor initialization is that it allows you to clearly hide any fields that are immutable by simply not providing a setter. I think this is important - if something shouldn't change then the lack of a setter communicates this very well. If you use setters for initialization, then this can become a pain. (Indeed in these situations I prefer to avoid the usual setting convention, I'd prefer a method like initFoo, to stress that it's something you should only do at birth.)

But with any situation there are exceptions. If you have a lot of constructor parameters things can look messy, particularly in languages without keyword parameters. It's true that a long constructor is often a sign of an over-busy object that should be split, but there are cases when that's what you need.

If you have multiple ways to construct a valid object, it can be hard to show this through constructors, since constructors can only vary on the number and type of parameters. This is when Factory Methods come into play, these can use a combination of private constructors and setters to implement their work. The problem with classic Factory Methods for components assembly is that they are usually seen as static methods, and you can't have those on interfaces. You can make a factory class, but then that just becomes another service instance. A factory service is often a good tactic, but you still have to instantiate the factory using one of the techniques here.

Constructors also suffer if you have simple parameters such as strings. With setter injection you can give each setter a name to indicate what the string is supposed to do. With constructors you are just relying on the position, which is harder to follow.

If you have multiple constructors and inheritance, then things can get particularly awkward. In order to initialize everything you have to provide constructors to forward to each superclass constructor, while also adding you own arguments. This can lead to an even bigger explosion of constructors.

Despite the disadvantages my preference is to start with constructor injection, but be ready to switch to setter injection as soon as the problems I've outlined above start to become a problem.

This issue has led to a lot of debate between the various teams who provide dependency injectors as part of their frameworks. However it seems that most people who build these frameworks have realized that it's important to support both mechanisms, even if there's a preference for one of them.

Code or configuration files

A separate but often conflated issue is whether to use configuration files or code on an API to wire up services. For most applications that are likely to be deployed in many places, a separate configuration file usually makes most sense. Almost all the time this will be an XML file, and this makes sense. However there are cases where it's easier to use program code to do the assembly. One case is where you have a simple application that's not got a lot of deployment variation. In this case a bit of code can be clearer than separate XML file.

A contrasting case is where the assembly is quite complex, involving conditional steps. Once you start getting close to programming language then XML starts breaking down and it's better to use a real language that has all the syntax to write a clear program. You then write a builder class that does the assembly. If you have distinct builder scenarios you can provide several builder classes and use a simple configuration file to select between them.

I often think that people are over-eager to define configuration files. Often a programming language makes a straightforward and powerful configuration mechanism. Modern languages can easily compile small assemblers that can be used to assemble plugins for larger systems. If compilation is a pain, then there are scripting languages that can work well also.

It's often said that configuration files shouldn't use a programing language because they need to be edited by non-programmers. But how often is this the case? Do people really expect non-programmers to alter the transaction isolation levels of complex server-side application? Non-language configuration files work well only to the extent they are simple. If they become complex then it's time to think about using a proper programming language.

One thing we're seeing in the Java world at the moment is a cacophony of configuration files, where every component has its own configuration files which are different to everyone else's. If you use a dozen of these components, you can easily end up with a dozen configuration files to keep in sync.

My advice here is to always provide a way to do all configuration easily with a programmatic interface, and then treat a separate configuration file as an optional feature. You can easily build configuration file handling to use the programmatic interface. If you are writing a component you then leave it up to your user whether to use the programmatic interface, your configuration file format, or to write their own custom configuration file format and tie it into the programmatic interface

Separating Configuration from Use

The important issue in all of this is to ensure that the configuration of services is separated from their use. Indeed this is a fundamental design principle that sits with the separation of interfaces from implementation. It's something we see within an object-oriented program when conditional logic decides which class to instantiate, and then future evaluations of that conditional are done through polymorphism rather than through duplicated conditional code.

If this separation is useful within a single code base, it's especially vital when you're using foreign elements such as components and services. The first question is whether you wish to defer the choice of implementation class to particular deployments. If so you need to use some implementation of plugin. Once you are using plugins then it's essential that the assembly of the plugins is done separately from the rest of the application so that you can substitute different configurations easily for different deployments. How you achieve this is secondary. This configuration mechanism can either configure a service locator, or use injection to configure objects directly.

--------------------------------------------------------------------------------

Some further issues

In this article, I've concentrated on the basic issues of service configuration using Dependency Injection and Service Locator. There are some more topics that play into this which also deserve attention, but I haven't had time yet to dig into. In particular there is the issue of life-cycle behavior. Some components have distinct life-cycle events: stop and starts for instance. Another issue is the growing interest in using aspect oriented ideas with these containers. Although I haven't considered this material in the article at the moment, I do hope to write more about this either by extending this article or by writing another.

You can find out a lot more about these ideas by looking at the web sites devoted to the lightweight containers. Surfing from the picocontainer and spring web sites will lead to you into much more discussion of these issues and a start on some of the further issues.

--------------------------------------------------------------------------------

Concluding Thoughts

The current rush of lightweight containers all have a common underlying pattern to how they do service assembly - the dependency injector pattern. Dependency Injection is a useful alternative to Service Locator. When building application classes the two are roughly equivalent, but I think Service Locator has a slight edge due to its more straightforward behavior. However if you are building classes to used in multiple applications then Dependency Injection is a better choice.

If you use Dependency Injection there are a number of styles to choose between. I would suggest you follow constructor injection unless you run into into one of the specific problems with that approach, in which case switch to setter injection. If you are choosing to build or obtain a container, look for one that supports both constructor and setter injection.

The choice between Service Locator and Dependency Injection is less important than the principle of separating service configuration from the use of services within an application.

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

Acknowledgements

My sincere thanks to the many people who've helped me with this article. Rod Johnson, Paul Hammant, Joe Walnes, Aslak Helles?on Tirs鮠and Bill Caputo helped me get to grips with these concepts and commented on the early drafts of this article. Berin Loritsch and Hamilton Verissimo de Oliveira provided some very helpful advice on how Avalon fits in. Dave W Smith persisted in asking questions about my initial interface injection configuration code and thus made me confront the fact that it was stupid.

Significant Revisions

23 Jan 04: Redid the configuration code of the interface injection example.

16 Jan 04: Added a short example of both locator and injection with Avalon.

14 Jan 04: First Publication

--------------------------------------------------------------------------------

   

--------------------------------------------------------------------------------

© Copyright Martin Fowler, all rights reserved

(转帖)Spring Gossip: Inversion of Control

在翻译一篇涉及Spring的文章,里面有个概念叫作:Inversion of Control,我觉得这篇文章解释很透。就贴在这里了。

(转自:http://caterpillar.onlyfun.net/Gossip/SpringGossip/IOC.html)

现在还没有专门的计划去学习Spring,就把它统归在“学习java”这个大的分类里,以后再转到合适的目标下。(需要完善日记重新归类的功能)

From Gossip@caterpillar

Spring Gossip: Inversion of Control

Spring 的核心概念是 IoC,IoC 的抽象概念是「依賴關係的轉移」,像是「高層模組不應該依賴低層模組,而是模組都必須依賴於抽象」是 IoC 的一種表現,「實現必須依賴抽象,而不是抽象依賴實現」也是 IoC 的一種表現,「應用程式不應依賴於容器,而是容器服務於應用程式」也是 IoC 的一種表現。

IoC 全名 Inversion of Control,如果中文硬要翻譯過來的話,就是「控制反轉」。初看 IoC,從字面上不容易瞭解其意義,我覺得要瞭解 IoC,要先從 Dependency Inversion 開始瞭解,也就是依賴關係的反轉。

Dependency Inversion The Dependency Inversion Principle 有清楚的解釋。

簡單的說,在模組設計時,高層的抽象模組通常是與業務相關的模組,它應該具有重用性,而不依賴於低層的實作模組,例如如果低層模組原先是軟碟存取模式,而高層模組是個存檔備份的需求,如果高層模組直接叫用低層模組的函式,則就對低層模組產生了依賴關係。

舉個例子,例如下面這個程式:

#include <floppy.h>

....

void save() {

        ....

        saveToFloppy()

    }

}

由於save()程式依賴於依賴於saveToFloppy(),如果今天要更換低層的存儲模組為Usb碟,則這個程式沒有辦法重用,必須加以修改才行,低層模組的更動造成了高層模組也必須跟著更動,這不是一個好的設計方式,在設計上希望模組都依賴於模組的抽象,這樣才可以重用高層的業務設計。

如果以物件導向的方式來設計,依賴反轉(Dependency Inversion)的解釋變為程式不應依賴實作,而是依賴於抽象,實作必須依賴於抽象。來看看下面這個 Java 程式:

public class BusinessObject {

    private FloppyWriter writer = new FloppyWriter();

    ....

   

    public void save() {

        ...

        writer.saveToFloppy();

    }

}

在這個程式中,BusinessObject 的存檔依賴於實際的 FloppyWriter,如果今天想要將存檔改為存至 Usb 碟,則必須修改或繼承 BusinessObject 進行擴展,而無法直接使用BusinessObject。

如果透過介面的宣告,可以改進此一情況,例如:

public interface IDeviceWriter {

    public void saveToDevice();

}

public class BusinessObject {

    private IDeviceWriter writer;

    public void setDeviceWriter(IDeviceWriter writer) {

        this.writer = writer;

    }

    public void save() {

        ....

        writer.saveToDevice();

    }

}

這樣一來,BusinessObject 就是可重用的,如果今天有存儲至 Floppy 或 Usb 碟的需求,只要實作 IDeviceWriter 即可,而不用修改 BusinessObject:

public class FloppyWriter implement IDeviceWriter {

    public void saveToDevice() {

        ....

        // 實際儲存至Floppy的程式碼

    }

}

public class UsbDiskWriter implement IDeviceWriter {

    public void saveToDevice() {

        ....

        // 實際儲存至UsbDisk的程式碼

    }

}

從這個角度來看,Dependency Inversion 的意思即是程式不依賴於實作,而是程式與實作都要依賴於抽象。

IoC 的 Control 是控制的意思,其實其背後的意義也是一種依賴關係的轉移,如果A依賴於B,其意義即是B擁有控制權,您想要轉移這種關係,所以依賴關係的反轉即是控制關係的反轉,藉由控制關係的轉移,可以獲得元件的可重用性,在上面的 Java 程式中,整個控制權從實際的 FloppyWriter 轉移至抽象的 IDeviceWriter 介面上,使得BusinessObject、FloppyWriter、UsbDiskWriter 這幾個實現依賴於抽象的 IDeviceWriter 介面。

程式的業務邏輯部份應是可以重用的,不應受到所使用框架或容器的影響,因為可能轉移整個業務邏輯至其它的框架或容器,如果業務邏輯過於依賴容器,則轉移至其它的框架或容器時,就會發生困難。

IoC 在容器的角度,可以用這麼一句好萊塢名言來代表:"Don't call me, I'll call you." 以程式的術語來說的話,就是「不要向容器要求您所需要的(物件)資源,容器會自動將這些物件給您!」。IoC 要求的是容器不侵入應用程式本身,應用程式本身提供好介面,容器可以透過這些介面將所需的資源注至至程式中,應用程式不向容器主動要求資源,故而不會依賴於容器的元件,應用程式本身不會意識到正被容器使用,可以隨時從容器中脫離轉移而不用作任何的修改,而這個特性正是一些業務邏輯中間件最需要的。

怎么样处理异常?

  处理异常有两种基本的方式:在程序内部捕获它并处理

    try{}

   catch(){}

   或者:在方法的异常规范中声明,告诉上一层的程序,本代码会掷出异常,请处理

  throws Exception{}

   但是,怎么样选择这两种方法呢?

  我看了一下thinking in java 3rd

  里面有一段关于处理方法的选择的话附于后:

  我觉得可以理解下面一些原则:

  1、目的:把处理异常的部分和功能部分分开,使系统易于理解和维护;

  2、原则:你如果不知道怎么处理一个异常就不要捕获它(而把它交给上级处理);

  3、但是具体的处理方式仍是灵活多变的,In this section we’ll look at some of the issues and complications arising from checked exceptions, and options that you have when dealing with them.

所以,我现在只有在利用原则2的情况下使代码尽可能的简单。

  4、最后那段话不大明白,好像是说从原来C风格的异常处理转过来的人会感到有很大的利益的改变,但是作者感到当它使用起来不大方便的时候又有点迷惑了。最后写了一句什么:“所以的模型都是错的,一些是有用的”。是什么意思?世上没有十全十美的方法吗?

Alternative approaches

An exception-handling system is a trap door that allows your program to abandon execution of the normal sequence of statements. The trap door is used when an “exceptional condition” occurs, such that normal execution is no longer possible or desirable. Exceptions represent conditions that the current method is unable to handle. The reason exception handling systems were developed is because the approach of dealing with each possible error condition produced by each function call was too onerous, and programmers simply weren’t doing it. As a result, they were ignoring the errors. It’s worth observing that the issue of programmer convenience in handling errors was a prime motivation for exceptions in the first place. Feedback

One of the important guidelines in exception handling is “don’t catch an exception unless you know what to do with it.” In fact, one of the important goals of exception handling is to move the error-handling code away from the point where the errors occur. This allows you to focus on what you want to accomplish in one section of your code, and how you’re going to deal with problems in a distinct separate section of your code. As a result, your mainline code is not cluttered with error-handling logic, and it’s much easier to understand and maintain. Feedback

Checked exceptions complicate this scenario a bit, because they force you to add catch clauses in places where you may not be ready to handle an error. This results in the “harmful if swallowed” problem:

try {

  // ... to do something useful

} catch(ObligatoryException e) {} // Gulp!

Programmers (myself included, in the first edition of this book) would just do the simplest thing, and swallow the exception—often unintentionally, but once you do it, the compiler has been satisfied, so unless you remember to revisit and correct the code, the exception will be lost. The exception happens, but it vanishes completely when swallowed. Because the compiler forces you to write code right away to handle the exception, this seems like the easiest solution even though it’s probably the worst thing you can do. Feedback

Horrified upon realizing that I had done this, in the second edition I “fixed” the problem by printing the stack trace inside the handler (as is still seen—appropriately—in a number of examples in this chapter). While this is useful to trace the behavior of exceptions, it still indicates that you don’t really know what to do with the exception at that point in your code. In this section we’ll look at some of the issues and complications arising from checked exceptions, and options that you have when dealing with them. Feedback

This topic seems simple. But it is not only complicated, it is also an issue of some volatility. There are people who are staunchly rooted on either side of the fence and who feel that the correct answer (theirs) is blatantly obvious. I believe the reason for one of these positions is the distinct benefit seen in going from a poorly-typed language like pre-ANSI C to a strong, statically-typed language (that is, checked at compile-time) like C++ or Java. When you make that transition (as I did), the benefits are so dramatic that it can seem like strong static type checking is always the best answer to most problems. My hope is to relate a little bit of my own evolution, that has brought the absolute value of strong static type checking into question; clearly, it’s very helpful much of the time, but there’s a fuzzy line we cross when it begins to get in the way and become a hindrance (one of my favorite quotes is: “All models are wrong. Some are useful.”). Feedback

(转帖)如何在Web工程中实现任务计划调度

转自:http://www.javaresearch.org/article/showarticle.jsp?column=2&thread=12337

 首页 » 研究文集 » J2EE综合   搜索标题相关文章      发表评论     开始监控     加入收藏夹 

如何在Web工程中实现任务计划调度

nbDeveloper 原创  (参与分:4690,专家分:120)   发表:2004-02-23 22:53   更新:2004-02-26 08:19   版本:1.0   阅读:4263次 

 

    好多朋友用过Windows的任务计划,也有不少程序迷自己曾写过时钟报警、系统自动关机等趣味程序,可却很少有朋友在Web工程中实现过类似功能。今天有空把笔者先前曾在Tomcat上实现的类似功能,搬出来与大家共享。

    早在几年前,我公司跟某市财政局合作项目开发,为加强财政局对所属单位财务状况的有效监管,开发、实施了财政局数据中心项目。此项目采用B/S加C/S混合结构模式。财政局Web服务器上架设数据同步接收装置,由市属单位每天下班前把财务信息通过HTTP协议上传至财政局中心服务器,与Web服务器上的接收装置对接。财政局内部各部门需要查阅大量财务信息,获取完备的市属单位当前财务状况信息,各部门按职能划分,需要准确的获取各部门各自所关注的汇总信息,以财政报表的形式提供。

    因财政数据量大,实时计算财政报表速度较慢,当初就考虑用报表缓存来减轻服务器的负担,但用缓存需要一个合理的缓存更新机制。考虑到各市属单位每天下班前才把财务数据上传,财政局每天所查看到的财务信息其实并不包括当天(除非有某位领导等到所属单位全部上传完之后才来查看信息,应该已经下班了),所以要是能实现任务计划调度,在每晚深夜把当天及历史财务信息汇总,更新缓存,速度瓶颈不就解决了吗。

    当时由于系统核心是基于Web部署的,报表计算引擎也相应的部署在Tomcat容器上,因此如果想要借用Windows的任务计划来实现定时计算,就需要额外编写普通桌面应用程序接口,稍显复杂。于是就琢磨着想在Web上实现,经过查阅较多相关资料,发现Java定时器(java.util.Timer)有定时触发计划任务的功能,通过配置定时器的间隔时间,在某一间隔时间段之后会自动有规律的调用预先所安排的计划任务(java.util.TimerTask)。另外,由于我们希望当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器能在每晚深夜触发一次报表计算引擎。因此定时器的存放位置也值得考查,不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟Servlet上下文有关的侦听器就最合适不过了,通过在工程的配置文件中加以合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。

    下面就Servlet侦听器结合Java定时器来讲述整个实现过程。要运用Servlet侦听器需要实现javax.servlet.ServletContextListener接口,同时实现它的contextInitialized(ServletContextEvent event)和contextDestroyed(ServletContextEvent event)两个接口函数。考虑定时器有个建立和销毁的过程,看了前面两个接口函数,就不容置疑的把建立的过程置入contextInitialized,把销毁的过程置入contextDestroyed了。

    我把ServletContextListener的实现类取名为ContextListener,在其内添加一个定时器,示例代码如下所示(为考虑篇幅,仅提供部分代码供读者参考):

    private java.util.Timer timer = null;

    public void contextInitialized(ServletContextEvent event) {

        timer = new java.util.Timer(true);

        event.getServletContext().log("定时器已启动");        

         timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000);

        event.getServletContext().log("已经添加任务调度表");

    }

    public void contextDestroyed(ServletContextEvent event) {

        timer.cancel();

        event.getServletContext().log("定时器销毁");

    }

    以上代码中, timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000)这一行为定时器调度语句,其中MyTask是自定义需要被调度的执行任务(在我的财政数据中心项目中就是报表计算引擎入口),从java.util.TimerTask继承,下面会重点讲述,第三个参数表示每小时(即60*60*1000毫秒)被触发一次,中间参数0表示无延迟。其它代码相当简单,不再详细说明。

   下面介绍MyTask的实现,上面的代码中看到了在构造MyTask时,传入了javax.servlet.ServletContext类型参数,是为记录Servlet日志方便而传入,因此需要重载MyTask的构造函数(其父类java.util.TimerTask原构造函数是没有参数的)。在timer.schedule()的调度中,设置了每小时调度一次,因此如果想实现调度任务每24小时被执行一次,还需要判断一下时钟点,以常量C_SCHEDULE_HOUR表示(晚上12点,也即0点)。同时为防止24小时执行下来,任务还未执行完(当然,一般任务是没有这么长的),避免第二次又被调度以引起执行冲突,设置了当前是否正在执行的状态标志isRunning。示例代码如下所示:

    private static final int C_SCHEDULE_HOUR   = 0;

    private static boolean isRunning = false;

         private ServletContext context = null;

    public MyTask(ServletContext context) {

        this.context = context;

    }

    public void run() {

        Calendar cal = Calendar.getInstance();        

        if (!isRunning)  {           

            if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) {            

                    isRunning = true;                

                context.log("开始执行指定任务");

                

                //TODO 添加自定义的详细任务,以下只是示例

                int i = 0;

                while (i++ < 10) {

                    context.log("已完成任务的" + i + "/" + 10);

                }

                isRunning = false;

                context.log("指定任务执行结束");               

            }            

        } else {

            context.log("上一次任务执行还未结束");

        }

    }

    上面代码中“//TODO……”之下四行是真正被调度执行的演示代码(在我的财政数据中心项目中就是报表计算过程),您可以换成自己希望执行的语句。

到这儿,ServletContextListener和MyTask的代码都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:

    <listener>

        <listener-class>com.test.ContextListener</listener-class>

    </listener>

    当然,上面的com.test得换成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任务会在每晚12点至凌晨1点之间被执行,上面的代码会在Tomcat的日志文件中记录如下:

2003-12-05 0:21:39 开始执行指定任务

2003-12-05 0:21:39 已完成任务的1/10

    ……

2003-12-05 0:21:39 已完成任务的10/10

2003-12-05 0:21:39 指定任务执行结束

    以上代码在Tomcat 4.1.29以及Tomcat 5.0.16上调试通过。如果您需要完整代码,请通过nbDeveloper@hotmail.com与我联系。

 

 

 

(转帖)servlet 相关的Listener应用(内含web程序的定时器)

转自:http://www.mscenter.edu.cn/blog/wangpeng/archive/2005/05/07/2268.aspx

servlet 相关的Listener应用

ZhangLiHai.Com Blog

servlet 相关的Listener应用

 

张利海 于 2004年11月22日 23:27 发表 

关键词 : servlet listener timer 定时器

从作用域范围来说,Servlet的作用域有ServletContext,HttpSession,ServletRequest.

Context范围:

   

ServletContextListener:

对一个应用进行全局监听.随应用启动而启动,随应用消失而消失主要有两个方法:

contextDestroyed(ServletContextEvent event)

 在应用关闭的时候调用

contextInitialized(ServletContextEvent event)

在应用启动的时候调用

这个监听器主要用于一些随着应用启动而要完成的工作,也就是很多人说的我想在容器

启动的时候干..........

一般来说对"全局变量"初始化,如

public void contextInitialized(ServletContextEvent event){

    ServletContex sc = event.getServletContext();

    sc.setAttribute(name,value);

}

以后你就可以在任何servlet中getServletContext().getAttribute(name);

我最喜欢用它来做守护性工作,就是在contextInitialized(ServletContextEvent event)

方法中实现一个Timer,然后就让应用在每次启动的时候让这个Timer工作:

public void contextInitialized(ServletContextEvent event){

    timer = new Timer();

    timer.schedule(new TimerTask(){

        public void run(){

            //do any things

        }

    },0,时间间隔);

}

    有人说Timer只能规定从现在开始的多长时间后,每隔多久做一次事或在什么时间做

一次事,那我想在每月1号或每天12点做一项工作如何做呢?

你只要设一个间隔,然后每次判断一下当时是不是那个时间段就行了啊,比如每月一号做,那你

时间间隔设为天,即24小时一个循环,然后在run方法中判断当时日期new Date().getDate()==1

就行了啊.如果是每天的12点,那你时间间隔设为小时,然后在run中判断new Date().getHour()

==12,再做某事就行了.

ServletContextAttributeListener:

这个监听器主要监听ServletContex对象在setAttribute()和removeAttribute()的事件,注意

也就是一个"全局变量"在被Add(第一次set),replace(对已有的变量重新赋值)和remove的时候.

分别调用下面三个方法:

public void attributeAdded(ServletContextAttributeEvent scab)这个方法不仅可以知道

哪些全局变量被加进来,而且可获取容器在启动时自动设置了哪些context变量:

public void attributeAdded(ServletContextAttributeEvent scab){

    System.out.println(scab.getName());

}

  public void attributeRemoved(ServletContextAttributeEvent scab)

  public void attributeReplaced(ServletContextAttributeEvent scab)

 

 

Session范围:

HttpSessionListener:

这个监听器主要监听一个Session对象被生成和销毁时发生的事件.对应有两个方法:

  public void sessionCreated(HttpSessionEvent se)

  public void sessionDestroyed(HttpSessionEvent se)

  一般来说,一个session对象被create时,可以说明有一个新客端进入.可以用来粗略统计在线人

数,注意这不是精确的,因为这个客户端可能立即就关闭了,但sessionDestroyed方法却会按一定

的策略很久以后才会发生.

HttpSessionAttributeListener:

和ServletContextAttributeListener一样,它监听一个session对象的Attribut被Add(一个特定

名称的Attribute每一次被设置),replace(已有名称的Attribute的值被重设)和remove时的事件.

对就的有三个方法.

  public void attributeAdded(HttpSessionBindingEvent se)

  public void attributeRemoved(HttpSessionBindingEvent se)

  public void attributeReplaced(HttpSessionBindingEvent se)

  上面的几个监听器的方法,都是在监听应用逻辑中servlet逻辑中发生了什么事,一般的来说.

我们只要完成逻辑功能,比如session.setAttribute("aaa","111");我只要把一个名为aaa的变量

放在session中以便以后我能获取它,我并不关心当session.setAttribute("aaa","111");发生时

我还要干什么.(当然有些时候要利用的),但对于下面这个监听器,你应该好好发解一下:

HttpSessionBindingListener:

上面的监听器都是作为一个独立的Listener在容器中控制事件的.而HttpSessionBindingListener

对在一对象中监听该对象的状态,实现了该接口的对象如果被作为value被add到一个session中或从

session中remove,它就会知道自己已经作为一个session对象或已经从session删除,这对于一些非

纯JAVA对象,生命周期长于session的对象,以及其它需要释放资源或改变状态的对象非常重要.

比如:

session.setAttribute("abcd","1111");

以后session.removeAttribute("abcd");因为abcd是一个字符中,你从session中remove后,它就会

自动被垃圾回收器回收,而如果是一个connection:(只是举例,你千万不要加connection往session

中加入)

session.setAttribute("abcd",conn);

以后session.removeAttribute("abcd");这时这个conn被从session中remove了,你已经无法获取它

的句柄,所以你根本没法关闭它.而在没有remove之前你根本不知道什么时候要被remove,你又无法

close(),那么这个connection对象就死了.另外还有一些对象可以在被加入一个session时要锁定

还要被remove时要解锁,应因你在程序中无法判断什么时候被remove(),add还好操作,我可以先加锁

再add,但remove就后你就找不到它的句柄了,根本没法解锁,所以这些操作只能在对象自身中实现.

也就是在对象被add时或remove时通知对象自己回调相应的方法:

MyConn extends Connection implements HttpSessionBindingListener{

  public void valueBound(HttpSessionBindingEvent se){

    this.initXXX();

  }

  public void valueUnbound(HttpSessionBindingEvent se){

    this.close();

  }

}

session.setAttribute("aaa",new MyConn());

这时如果调用session.removeAttribute("aaa"),则触发valueUnbound方法,就会自动关闭自己.

而其它的需要改变状态的对象了是一样.

另外还有一个HttpSessionActivationListener监听器是实现分布式应用中session同步的.不作

多介绍,如果有要实现该功能的朋友可以和我联系.

在servlet2.4中,对于request范围已经实现对应的监听器:

ServletRequestListener,ServletRequestAttributeListener

但没有找到好的容器的支持所以没有做过多的测试.虽然从API可以掌握99%,但没有经过真正的

测试我是不会仅把API抄出来的.以后我会补齐这方面的内容

原作者:Axman