爱因斯坦曾经说:“任何事情都应该越简单越好,而不是比较简单。”实际上,科学真理的目的就是在假设的前提下去简化一个理论,这样,人们可以去关注真正重要的问题。在企业软件开发中,道理是一样的。
简化企业软件开发的一个关键是,提供一个这样的应用框架:它可以使开发人员不用关注于很多复杂的问题,比如事务处理、安全和持久化等。一个设计良好的框架将提升代码的可复用性,提高开发者的效率,并得到更高质量的软件。然而,目前J2EE 1.4下的EJB 2.1 框架被广泛认为是设计较差而且过度复杂的。不满足于EJB2.1框架,JAVA开发者使用了很多其他的中间件服务产品。最值得关注的是,以下两个框架吸引了大量开发者的兴趣和积极反馈。这两个框架很可能成为未来企业JAVA应用开发框架的选择。
Spring框架是一个广受欢迎的但是非标准的开源框架。它主要由Interface21公司开发和控制。Spring框架的体系结构是基于注射依赖(DI)模式。Spring框架使用了大量的XML配置文件,它可以独立应用,或者在现有的应用服务器上工作。
EJB 3.0框架是JCP定义的并且被所有主流J2EE提供商支持的标准框架。EJB 3.0规范的预发布版本目前已经有开源的和商业的实现,如JBOSS和ORACLE。EJB 3.0大量使用了JAVA注解(Java annotations,是JDK1.5提供的新功能。译者注)
这两个框架有着一个共同的核心设计理念:它们的目标是为松耦合的POJO类提供中间件服务。框架通过在运行时截取执行环境,或将服务对象注射给POJO类的方式,将应用服务和POJO类“连接”起来。POJO类本身并不关注如何“连接”,而且也很少依赖于框架。这样,开发者可以将注意力集中在业务逻辑上,可以对他们的POJO类进行与框架无关的单元测试。并且,由于POJO类不需要继承框架的类或实现框架提供的接口,开发者可以在更加灵活性的基础上构建继承体系,和搭建应用。
尽管有着共同的理念,但这两个框架采取了不同的方式来提供POJO服务。由于已经出版了大量的比较Spring与EJB2.1或者EJB3.0与EJB2.1的书籍和文章,而没有关于比较Spring和EJB3.0的认真研究,因此,本文将考察它们之间几个关键的不同,讨论他们优缺点。本文谈到的主题同样适用于其他不太有名的但同样提供“松耦合POJO” 设计的企业中间件框架。我希望,这篇文章可以帮助你选者最合适的你需求的框架。
提供商无关性
开发者选择JAVA平台的一个最重要的原因就是它的提供厂商无关性。EJB 3.0是一个被设计为对提供商没有依赖性的开放的标准。EJB 3.0规范由企业JAVA社区的主流开源组织和厂商共同编写和支持的。EJB 3.0框架使开发者的应用程序实现可以独立于应用服务器。比如,JBoss的EJB 3.0的实现是基于Hibernate的,Oracle的EJB 3.0实现是基于TopLink的,但是,在JBoss或者Oracle上跑应用程序,开发者既不需要去学习Hibernate,也不需要学习TopLink提供的独特API。厂商无关性使EJB 3.0框架区别于当前其他任何的POJO中间件框架。
然而,就象很多EJB 3.0的批评者很快指出的一样,目前EJB 3.0规范正在编写还未完全完成最终发布版。很有可能,还需要1至2年,EJB 3.0才会被主流J2EE厂商完全接受。但是,就算你的应用服务器本身不支持EJB 3.0,你也可以通过下载和安装一个“可嵌入的” EJB 3.0产品,来使你的应用服务器支持EJB 3.0应用。比如,JBoss“可嵌入的” EJB 3.0产品是开源的,它可以运行在任何兼容J2SE-5.0环境下(如你的应用服务器),目前处于Beta版测试中。其他厂商同样可以快速发布他们自己的可嵌入EJB 3.0产品,特别是规范中“数据持久化”部分。
另一方面,Spring一直是一个非标准的技术,而且在可以预计的未来仍将如此。尽管你在任何应用服务器都上可以使用Spring框架,但基于Spring的应用仍然被限制于Spring本身和在你的应用中使用到的Spring提供的各种特别服务。
由于Spring框架是一个开源项目,因此,它使用的配置文件XML格式和开发接口都是私有的。当然,这种限制不仅体现在Spring框架中,其他任何非标准产品都会有这种限制。但是,你的Spring应用的长期生存能力将依赖于Spring项目本身(或者说Interface 21公司,因为它雇佣了大多数的Spring核心开发人员)。并且,如果你使用了Spring提供的特殊服务,如Spring事务管理器或者Spring MVC,你同样被限制于Spring提供的API。
并且,Spring应用是知道后端服务提供者的(即应用程序是知道服务提供者的,这样应用程序将会在一定程度上依赖于服务提供方:译者注)。例如,对于数据持久化服务,Spring框架提供了不同的DAO和模板Helper类,用于JDBC、Hibernate,、iBatis和JDO。这样,假如你需要改变一个Spring应用的持久化服务提供者(如,从JDBC换到Hibernate),你将需要重构你的系统应用代码,来使用新的Helper类。
服务整合 Spring框架是建立在应用服务器和服务库之上,它的服务整合代码(如数据访问模板和Helper类)是基于框架的,并暴露给应用开发者。相反,EJB 3.0框架是紧密整合到应用服务器中的,它的服务整合代码是封装在一个标准的接口下的。
因此,EJB 3.0厂商可以轻松的优化整体性能和开发者体验。如,在JBoss的EJB 3.0实现中,当你通过实体管理器持久化一个实体BEAN POJO时,Hibernate session事务将在JTA事务提交时自动提交。通过使用简单的@PersistenceContext注解(例子参看后面文章),你可以甚至可以将实体管理器和其下的Hibernate事务绑定到一个有状态的session bean上。应用程序事务可以在一个session中跨越多个线程,在事务性的WEB应用中这是非常有用的,如多页面的购物车。
基于EJB 3.0 框架、Hibernate、和JBoss 内部Tomcat的紧密整合,上面提到的简单的整合的编程接口是可能的。Oracle的EJB 3.0框架和它内部的Toplink持久服务可以达到同样层次的整合。
EJB 3.0中整合服务的另一个好例子是集群支持。假如你部署一个EJB 3.0应用到一个集群服务器,所有的故障切换、负载均衡、分布式缓存、和状态复制服务对于应用程序来说,都是自动完成的。集群服务被隐藏在EJB 3.0编程接口之下,对于EJB 3.0开发者来说,这些服务都是完全透明的。
在Spring中,优化框架和服务之间交互更加困难一些。例如,想要用Spring的声明式事务服务来管理Hibernate事务,必须在XML配置文件中明确的配置Spring的事务管理器(TransactionManager)和Hibernate SessionFactory对象。Spring应用开发者必须自己管理跨越多个HTTP请求的事务。并且,没有简单的方法可以在Spring应用中实现集群服务
服务聚合的灵活性 由于Spring中的服务整合代码是作为编程接口暴露给应用开发者的,因此开发人员可以根据需要来聚合多个服务。这个特性使你可以集成一个你自己的“轻量”级应用服务器。Spring的一个通常的用法是将Tomcat和Hibernate连接起来来支持简单的数据库驱动的WEB应用程序。在这种情况下,Spring本身提供了事务管理服务,Hibernate提供了持久化服务,这种设置本身就创建了一个小型的应用服务器。
通常,EJB 3.0应用服务器不提供给开发者这种按照你的需要来选择服务的灵活性。大多数情况,你会得到一系列已经预先打包好的特性,其中有些你可能是不需要的。然而,如果应用服务器提供了模块内部的独特设计,就象JBOSS一样,你可以不去关心这些不必要的特性。在任何情况下,去定制一个全功能的应用服务器并不是一个琐碎而没有意义的工作。
当然,如果一个应用不是一个单一的结点,你将需要连接多个应用服务器提供的服务(如资源池、消息队列和集群)。这种情况下,从总的资源消耗上看,Spring框架就和任何EJB 3.0方案一样是“重量级”的。
为了进行容器外的单元测试,Spring的灵活的服务聚合也可以来连接假对象,来替代真的服务对象。在EJB 3.0应用中,大多数的组件都是简单POJO,他们可以容易进行容器外的单元测试。但是,如果要测试与容器服务相关的服务对象(如持久化实体管理器),更好的方式是进行容器内的测试,因为这样比使用假对象来替代的方式更加容易,更加健壮,而且更加准确。
XML vs. 注解
从应用开发者的角度来看,Spring的编程接口主要基于XML配置文件,而EJB 3.0则大量的使用了JAVA注解。XML文件可以表达复杂的关系,但是它们更加冗长而且不健壮。注解的方式很简单明了,但是很难去表达复杂的或者继承性的结构。
Spring和EJB 3.0分别选择了XML和注解方式,这取决于框架的体系结构:由于注释只能描述相当少的配置信息,只有一个预先整合好的框架(如大多数重要事情已经在框架中实现了)才能大量的使用注释作为它的配置选项。象我们讨论的一样,EJB 3.0满足了这些要求,而Spring作为一个一般的注射依赖框架,它没有做到这一点。
当然,由于EJB 3.0和Spring相互学习了很多特性,所以,它们都在某种层次上支持XML和注释。例如,EJB 3.0中可以应用XML配置文件来作为一个选择性的机制,用来改变注释的默认行为。注释也可以用来配置一些Spring服务。
研究XML和注释直接区别的最好的方式就是通过例子。在下面的几节中,我们将一起看一下EJB 3.0和Spring是如何为应用程序提供关键服务的。
声明式服务 EJB 3.0和Spring都将运行时服务(如事务管理、安全、日志、消息、和信息服务)连接给应用程序。由于这些服务同应用程序的业务逻辑并不是直接相关的,因此,它们不被应用程序本身来管理。相反,这些服务被服务容器(如EJB 3.0和Spring)以不可见的方式在运行时提供给应用程序。开发人员(或系统管理员)通过配置来告诉容器什么时候,以怎样的方式来应用这些服务。
EJB 3.0通过JAVA注解的方式来配置声明式服务,Spring则通过XML配置文件来完成。大多数情况下,EJB 3.0 的注解方式是应用这种服务的更加简单和优美的方式。下面是一个在EJB 3.0中对一个POJO的方法使用事务管理服务的例子。
public class Foo {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public bar () {
// do something ...
}
}
你可以对一段代码声明多个属性,并应用多个服务。下面是一个对EJB 3.0中POJO类同时使用事务管理服务和安全服务的例子。
@SecurityDomain("other")
public class Foo {
@RolesAllowed({"managers"})
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public bar () {
// do something ...
}
}
使用XML指定代码属性和配置声明服务将导致冗长的和不桅顶的配置文件。下面是Spring应用中一个XML元素的例子,它用来在Foo.bar()方法上应用一个非常简单的Hibernate事务。
<!-- Setup the transaction interceptor -->
<bean id="foo"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target">
<bean class="Foo"/>
</property>
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributeSource">
<ref bean="attributeSource"/>
</property>
</bean>
<!-- Setup the transaction manager for Hibernate -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<!-- you need to setup the sessionFactory bean in yet another XML element -->
<ref bean="sessionFactory"/>
</property>
</bean>
<!-- Specify which methods to apply transaction -->
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="bar">
</props>
</property>
</bean>
XML文件的复杂程度将随着你对同一个POJO类增加的拦截器的数量程几何增长。意识到了仅使用XML配置文件的限制性,Spring支持在JAVA源代码中使用Apache Commons metadata来指定事物属性。在最新的Spring 1.2中,JDK-1.5风格的注释也被支持。为了使用事务元数据,你需要为上面例子中的AttributesTransactionAttributeSource 改变一个transactionAttributeSource bean,并且增加一个附加的对元数据拦截器的设置。
<bean id="autoproxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource"
autowire="constructor"/>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor"
autowire="byType"/>
<bean id="transactionAdvisor"
class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"
autowire="constructor"/>
<bean id="attributes"
class="org.springframework.metadata.commons.CommonsAttributes"/>
当你有许多事务方法时,Spring元数据简化了transactionAttributeSource元素。但是它没有解决XML配置文件的根本问题:仍然需要冗长的、易错的事务拦截器,事务管理器,和事务属性。
注射依赖
中间件容器的一个主要优点是它们使得程序开发人员可以去构建松耦合的应用程序。服务使用者仅仅需要知道服务接口就可以使用服务。容器把具体的服务实现实例化,然后将它们提供给服务使用者。这样,容器可以在可替换的服务实现之间进行切换,而不改变服务接口和服务使用者代码。
注射依赖模式是实现松耦合应用程序的一个最好的方式。比起以前的方式,如通过JNDI进行查找或回调容器,注射依赖模式更容易使用,而且更加优美。使用注射依赖模式,框架扮演了构建服务的对象工厂角色,然后根据运行时的配置,把这些服务对象注射到应用程序的POJO类中。从程序开发人员的角度看,作为客户端使用者的POJO在需要使用服务对象前就自动的得到了它们。
Spring 和 EJB 3.0都提供了大量的DI模式支持。但是,它们之间也有着根本的不同。Spring支持了通常意义上的但是复杂的基于XML配置文件的注射依赖API;EJB 3.0支持的注射大多数通用服务对象(如,EJB和容器对象)和JNDI对象,它通过简单的JAVA注解来完成。
EJB 3.0的注射注解相当的简洁易用。@Resource标签注射大多数的通过服务对象和JNDI对象。下面的例子显示了如何将JNDI提供的服务器缺剩数据源对象注射给一个POJO的一个字段。DefaultDS是这个数据源的JNDI名字。myDb 变量在第一次被使用前就自动被赋予了正确的值。
public class FooDao {
@Resource (name="DefaultDS")
DataSource myDb;
// Use myDb to get JDBC connection to the database
}
在EJB 3.0中,注释@Resource不仅可以直接注射给属性变量,它也可以通过setter方法来完成注射。下面的例子将一个session上下文对象通过setter方法注射给使用者。应用程序不用显示的调用setter方法,在任何其他方法被调用前容器将调用setter方法完成注射。
@Resource
public void setSessionContext (SessionContext ctx) {
sessionCtx = ctx;
}
对于更复杂的服务对象,还有一些特殊的注射注解。例如,@EJB 注解被用来注射EJB stubs,@PersistenceContext注解被用来注射实体管理器对象,这些对象负责处理EJB 3.0实体Bean的数据访问操作。 下面的例子给出如何将一个实体管理器注射到一个有状态Session Bean中。@PersistenceContext注解的类型属性描述了被注射的的实体管理器有一个扩展的事务容器:它不会随着JTA事务管理器自动提交事务,因此它可以应用在当session中有多次操作的应用事务管理时。
@Stateful
public class FooBean implements Foo, Serializable {
@PersistenceContext(
type=PersistenceContextType.EXTENDED
)
protected EntityManager em;
public Foo getFoo (Integer id) {
return (Foo) em.find(Foo.class, id);
}
}
EJB 3.0 规范定义了可以通过注解来被注射使用的服务器资源。但是,它不支持用户自定义的POJO类之间的相互注射。
在Spring中,为了将服务对象注射到你的POJO类中,你首先需要定义一个setter方法(或有参数的构造函数) 。下面的例子演示了 POJO 类中一个Hibernate session 工厂的属性。
public class FooDao {
HibernateTemplate hibernateTemplate;
public void setHibernateTemplate (HibernateTemplate ht) {
hibernateTemplate = ht;
}
// Use hibernateTemplate to access data via Hibernate
public Foo getFoo (Integer id) {
return (Foo) hibernateTemplate.load (Foo.class, id);
}
}
因此,你可以指定容器如何得到这个服务,并且在运行时通过配置文件中XML元素的连接关系把它提供给POJO。下面的例子显示了连接一个数据源到一个Hibernate session 工厂、session 工厂到Hibernate模板对象、模板对象最后到应用程序POJO类,整个过程的XML配置。
Spring 代码复杂性的部分原因是,我们需要手工的去注射Hibernate相关类,然而,EJB 3.0 实体管理器被服务器自动管理和配置。但是,这使我们返回到了这样的讨论:Spring 不象EJB 3.0 一样,它不同服务紧密整合在一起。
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiname">
<value>java:comp/env/jdbc/MyDataSource</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="fooDao" class="FooDao">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
<!-- The hibernateTemplate can be injected into more DAO objects -->
尽管Spring中基于XML的注射依赖比较复杂,但是它非常强大。你可以注射任何POJO到另外的POJO中,包括程序中自定义的。
如果你确实想在EJB 3.0应用中使用Spring的注射依赖功能,你可以将一个Spring Bean工厂类通过JNDI注射到一个EJB中。在某些EJB 3.0 应用服务器中,厂商可能会定义一些非标准的API用来注射任意的POJO类。一个很好的例子是JBoss MicroContainer,它处理了AOP依赖性,因此它是甚至比Spring 更加通用。
结论
尽管Spring 和EJB 3.0的目标都是提供企业服务,使得POJO可以松耦合,但是它们实现的方式非常不同。在两个框架中注射依赖模式都有大量的应用。
通过EJB 3.0的标准方式、大量应用的注解、还有同应用服务器紧密整合性,这些提供了更高的厂商无关性和开发人员工作效率。Spring的以XML为中心的配置文件和注射依赖的连贯使用,允许开发人员去构造更加灵活的应用系统,并且可以同时与多个应用服务提供者同时工作。
感谢
作者感谢Stephen Chambers, Bill Burke, 和Andy Oliver 的有价值的评论.
参考
The Spring framework (参考CodeZoo: Spring)
EJB 3.0
JBoss EJB 3.0
Oracle Application Server EJB 3.0 Preview
Michael Juntao Yuan specializes in end-to-end enterprise solutions and is a mobile geek and avid open source supporter.
posted @
2005-08-22 10:13 Dave 阅读(226) |
评论 (0) |
编辑 收藏
bsh-deployer:将BeanShell脚本部署成JBoss服务。
cache-invalidation-service.xml:允许借助于JMS,而实现对EJB缓存的控制。
client-deployer-service.xml:部署J2EE应用客户。
ear-deployer.xml:部署J2EE EAR应用。
ejb-deployer.xml:部署J2EE EJB应用。
hsqldb-ds.xml:设置嵌入式Hypersonic数据库服务,并将其作为默认数据源。
http-invoker.sar:通过RMI/HTTP方式访问到MBean和EJB。
jboss-aop.deployer:提供AspectManagerService,并部署JBoss AOP应用。
jboss-hibernate.deployer:部署Hibernate存档(HAR文件)。
jboss-local-jdbc.rar和jboss-xa-jdbc.rar:集成JDBC驱动的JCA资源适配器,它们分别支持DataSource和XADataSource。但是,这并没有提供专有JCA实现。
jboss-ws4ee.sar:提供J2EE Web服务支持。
jbossjca-service.xml:JBoss JCA实现,使得在JBoss中部署JCA资源适配器成为可能。
jbossweb-tomcat50-sar:含有嵌入式Tomcat服务的展开SAR文件。它为JBoss提供了标准的Web容器。
jms:将JMS相关的服务聚集在一起,并放置在jms目录中。
hsqldb-jdbc-state-service.xml:使用HSQLDB管理状态。
hsqldb-jdbc2-service.xml:使用嵌入式HSQL数据库实现缓存和持久化。它还包含了JMS实现的核心服务,即DestinationManager MBean。
jbossmq-destinations-service.xml:供JBoss测试套件使用的JMS Topic和Queue。
jbossmq-service.xml:JMS其他服务,包括拦截器配置。
jms-ds.xml:将JBoss消息实现作为默认JMS提供商。并且,它还提供JCA配置信息,以供集成JBoss JCA和JMS资源适配器使用。
jms-ra.rar:资源适配器,供JCA处理JMS连接工厂使用。
jbossmq-httpil.sar:提供JMS调用层,从而实现HTTP方式使用JMS。
jvm-il-service.xml:配置本地JMS传输调用层,供本地JVM使用JMS。
uil2-service.xml:配置JMS版本2统一调用层。这是一种可靠的、自定义的、基于Socket的传输方式。推荐在不同JVM间使用它。
jmx-console.war:JMX控制台应用。前面讨论过。
jmx-invoker-server.xml:为远程访问JMX MBean服务器提供支持。
mail-ra.rar:为JavaMail提供资源适配器。
mail-service.xml:允许应用和服务在JBoss中使用JavaMail。请注意,邮件服务器相关信息必须由用户提供。
management:含有可更换管理服务的子目录。其中,包含有改进的Web控制台。
monitoring-service.xml:配置警告监听器,比如控制台监听器、E_mail监听器,等等。
properties-service.xml:设置JVM的全局系统属性(由System.getProperties返回)。
schedule-manager-service.xml和scheduler-service.xml:定时任务服务。
sqlexception-service.xml:为JDBC驱动提供标识一般性SQL异常。
uuid-key-generator.sar:生成唯一的、基于UUID的键。
all配置提供了其他配置没有提供的其他服务,用户可以将这些服务集成到各自的服务器配置中。具体如下:
cluster-service.xml:群集服务,包括JGroups集成服务、HA-JNDI、有状态会话Bean复制、CMP2缓存有效性服务。
deploy-hasingleton-service.xml:HASingletonDeployer MBean。用于确保群集中只有单个节点在deploy-hasingleton目录部署了服务。
deploy.last/farm-service.xml:farm群集部署服务。用于确保它在所有其他服务部署之后才部署其本身。
ebxmlrr-service.xml:JAXR注册服务实现。
iiop-service.xml:实现对CORBA、IIOP的支持。
jbossha-httpsession.sar:遗留的HTTP会话复制服务。
remoting-service.xml:还处于试验中的下一代分离式Invoker框架。
snmp-adaptor.sar:将JMX通知转换成SNMP陷阱。
tc5-cluster-service.xml:用于新的HTTP复制服务的TressCache配置。
posted @
2005-08-22 09:25 Dave 阅读(1207) |
评论 (1) |
编辑 收藏
目录结构:
bin:含有启动、停止以及其他系统相关脚本。在前面,本书已经讨论过启动JBoss应用服务器的run脚本。
client:存储供Java客户应用或者外部Web容器使用的配置文件和JAR文件。用户可以使用所需要的具体存档,或者仅仅使用jbossall-client.jar。
docs:含有JBoss引用的XML DTD文件(当然,还包括JBoss具体配置文件)。同时,还存在JCA(Java Connetor Architecture,Java连接器架构)实例配置文件,供设置不同数据库的数据源使用(比如MySQL、Oracle、Postgres)。
lib:包含运行JBoss微内核所需的JAR文件。请注意,不要往该目录添加用户自身的任何JAR文件。
server:包含的各个子目录都是不同的服务器配置。通过往run脚本后添加-c <config name>参数便能够指定不同的配置。接下来,来看看default服务器配置。
从根本上考虑,JBoss架构是由JMX MBean服务器、微内核、一套可插入式组件服务以及MBean构成的。这种架构使得,集成不同的配置变得更加简单,并且能够很灵活地满足用户的各自需求。用户不再需要一次性运行重量级的应用服务器。同时,用户可以删除不再需要使用的组件(这将从很大程度上减少服务器的启动时间),并且通过开发自己的MBean还能够集成其他服务到JBoss中。当然,如果是运行标准J2EE应用,则不用理会这些自定义工作。用户所需要的一切服务,JBoss发布版都包括了。
server目录下存在3个服务器实例配置:all、default以及minimal,它们各自提供了不同的服务集合。很显然,如果启动JBoss服务器时没有指定其他配置,则将使用default配置。
minimal:这是启动JBoss服务器所要求的最低配置。minimal配置将启动日志服务、JNDI服务器以及URL部署扫描器,以找到新的部署应用。对于那些不需要使用任何其他J2EE技术,而只是使用自定义服务的场合而言,则这种JMX/JBoss配置最适合。它仅仅是服务器,而不包含Web容器、不提供EJB和JMS支持。
default:默认配置,它含有大部分J2EE应用所需的标准服务。但是,它不含有JAXR服务、IIOP服务、或者其他任何群集服务。
all:提供了所有可用的服务。它包含RMI/IIOP和群集服务,default配置中没有提供群集服务。
用户也可以添加自身的服务器配置。最佳做法是,拷贝最接近用户需求的现有配置,然后修改其具体内容。比如,如果用户不需要使用消息服务,则只需要拷贝default目录,并重新命名为myconfig,然后删除jms子目录。最后,启动myconfig配置。
run -c myconfig
default服务器配置目录的具体内容:
conf:含有指定JBoss核心服务的jboss-service.xml文件。同时,还包括核心服务的其他配置文件。
data:Hypersonic数据库实例将数据存储在此处。JBossMQ(JMS的JBoss实现)也使用它存储消息。
deploy:用户将应用代码(JAR\WAR\EAR文件)部署在此处。同时,deploy目录也用于热部署服务(即,那些能够从运行服务器动态添加或删除的服务)和部署JCA资源适配器。因此,用户能够在deploy目录看到大量的配置文件。尤其是,用户能够看到JMX控制台应用(未打包的WAR文件),本书前面讨论过。JBoss服务器将定期扫描该目录,从而查找是否有组件更新或修改,从而自动完成组件的重新部署。本书后续章节将详细阐述部署细节。
lib:服务器配置所需的JAR文件。用户可以添加自身的库文件,比如JDBC驱动,等等。
log:日志信息将存储到该目录。JBoss使用Jakarta Log4j包作为其日志功能。同时,用户可以在应用中直接使用Log4j日志记录功能。
tmp:供部署器临时存储未打包应用使用,也可以作为其他用途。
work:供Tomcat编译JSP使用。
其中,data、log、tmp、work目录是JBoss创建的。如果用户没有启动过JBoss服务器,则这些目录不会被创建。
.
2.2.1 核心服务
当JBoss服务器启动时,首先会启动conf/jboss-service.xml文件指定的核心服务。
虽然通过conf/jboss-service.xml文件能够添加其他MBean服务,但是更好的办法是,将单独的配置文件放置在deploy目录中,因为这将使得用户的服务具有热部署能力。
2.2.2 日志服务
Log4j是JBoss使用的日志功能包。通过conf/log4j.xml文件能够控制JBoss的日志功能。
2.2.3 安全性服务
安全性域信息存储在login-config.xml文件中,其包含了许多安全性域定义。各个安全性域指定了许多JAAS登陆模块,供安全性域认证使用。当用户需要在应用中使用安全性时,需要在JBoss特定部署描述符jboss.xml或jboss-web.xml中指定待使用的安全性域名。
2.2.4 其他服务
deploy目录放置的服务不是核心服务,但具有热部署能力。用户可以通过XML描述符文件(*-service.xml)或JBoss服务存档(SAR)文件给出服务。SAR同时含有XML描述符和服务所要求的其他资源(比如,类、JAR库文件以及其他存档),而且SAR是以单个存档文件给出的。
posted @
2005-08-19 17:47 Dave 阅读(899) |
评论 (2) |
编辑 收藏
投资是一种追求未来货币增值的经济行为。
新中国的第一张股票:1984年12月发行的上海飞乐音响公司的股票。
90年12月19日,上证交易所开业
posted @
2005-08-19 15:36 Dave 阅读(155) |
评论 (0) |
编辑 收藏
Unlike ad hoc non-EJB architectures, it is similar to EJB architectures in being centered around a layer of managed business service objects. However, this is where the similarity ends. Instead of running inside an EJB container, business objects run inside a lightweight container. A lightweight container isn't tied to J2EE, so it can run in a web container, a stand-alone application, or even an EJB container if necessary. It also isn't tied to the Servlet API, like an MVC web framework, which is a poor choice for managing business objects. Lightweight containers have negligible startup cost and eliminate the deployment step of EJB.
Lightweight containers provide a way to manage and locate business objects. No longer is there any need for JNDI lookups, custom service locators, or Singletons: the lightweight container provides a registry of application objects.
Lightweight containers are both less invasive and more powerful than an EJB container where co-located applications are concerned.
To provide a complete solution, the lightweight container must provide enterprise services such as transaction management. Typically this will invoke AOP interception: transparently weaving in additional behavior, such as transaction management, before and after the execution of business methods.
From the user’s perspective, the web tier is provided by an MVC framework. We can use a dedicated
web framework such as Struts or WebWork, or—in the case of Spring—a web tier that can itself be managed
by the lightweight container and provide close integration with business objects.
Business objects will be POJOs, running inside the lightweight container. They may be “advised” via AOP interception to deliver enterprise services. Unlike EJBs, they don't usually need to depend on container
APIs, meaning that they are also usable outside any container. Business objects should be accessed
exclusively through their interfaces, allowing pluggability of business objects without changing calling
code.
Data access will use a lightweight O/R mapping layer providing transparent persistence, or JDBC via a
simplifying abstraction layer if O/R mapping adds little value.
StrengthsFollowing are some of the advantages of using this architecture:
(1) A simple but powerful architecture.
(2) As with local EJBs or an ad hoc non-EJB solution, horizontal scalability can be achieved by clustering
web containers. The limitations to scalability, as with EJB, will be session state management,
if required, and the underlying database. (However, databases such as Oracle 9i RAC can
deliver huge horizontal scalability independent on the J2EE tier.)
(3) Compared to an ad hoc non-EJB architecture, using a lightweight container reduces rather than
increases complexity. We don't need to write any container-specific code; cumbersome lookup
code is eliminated. Yet lightweight containers are easier to learn and configure than an EJB
container.
(4) Sophisticated declarative services can be provided by a lightweight container with an AOP
capability. For example, Spring's declarative transaction management is more configurable than
EJB CMT.
(5) This architecture doesn't require an EJB container. With the Spring Framework, for example,
you can enjoy enterprise services such as declarative transaction management even in a basic
servlet engine. (Whether you need an application server normally depends on whether you
need distributed transactions, and hence, JTA.)
(6) Highly portable between application servers.
(7) Inversion of Control allows the lightweight container to “wire up” objects, meaning that the complexity
of resource and collaborator lookup is removed from application code, and application
objects don't need to depend on container APIs. Objects express their dependencies on collaborators
through ordinary Java JavaBean properties or constructor arguments, leaving the IoC
container to resolve them at runtime, eliminating any need for tedious-to-implement and hardto-
test lookups in application code.IoC provides excellent ability to manage fine-grained business objects.
(8) Business objects are easy to unit test outside an application server, and some integration testing
may even be possible by running the lightweight container from JUnit tests. This makes it easy
to practice test first development.
WeaknessesFollowing are some of the disadvantages of using this architecture:
(1) Like a local EJB architecture, this architecture can't support remote clients without an additional
remoting facade. However, as with the local EJB architecture, this is easy enough to add, especially
if we use web services remoting (which is becoming more and more important). Only in
the case of RMI/IIOP remoting are remote EJBs preferable.
(2) There's currently no “standard” for lightweight containers comparable to the EJB specification.
However, as application objects are far less dependent on a lightweight container than EJBs are
on the EJB API, this isn't a major problem. Because application objects are plain Java objects,
with no API dependencies, lock-in to a particular framework is unlikely. There are no special
requirements on application code to standardize.
(3) This architecture is currently less familiar to developers than EJB architectures. This is a nontechnical
issue that can hamper its adoption. However, this is changing rapidly.
Implementation IssuesFollowing are some of the implementation issues you might encounter:
(1) Declarative enterprise services can be provided by POJOs using AOP, thus taking one of the best
features of EJB and applying it without most of the complexity of EJB.
(2) A good lightweight container such as Spring can provide the ability to scale down as well as up.
For example, Spring can provide declarative transaction management for a single database
using JDBC connections, without the use of JTA. Yet the same code can run unchanged in a different
Spring configuration taking advantage of JTA if necessary.
(3) A nice variation is ensuring that POJO business objects can be replaced by local EJBs without
changes in calling code. Spring provides this ability: all we need to do is create a local EJB with
a component interface that extends the business interface, if we wish to use EJB. These last two
points make this approach highly flexible, if requirements change. (This results largely from
good OO programming practice and the emphasis on interfaces.)
posted @
2005-08-18 16:19 Dave 阅读(199) |
评论 (0) |
编辑 收藏
建立信任
及时给予肯定
出错时调整注意力
表现管理学ABC
A=催化剂(activator)
任何引发表现的原因
B=行为(behavior)
发生的表现
C=结果(consequence)
你对所产生表现的反应
四种结果
1.没有反应
2.表示否定
3.调整指令
4.表示肯定
调整指令的方法
●尽可能快地、清晰而不带责备地指出错误
●解释错误的负面影响
●如果可以,将过错归结于没有清楚地解释工作任务
●详细地重新解释工作任务,并确保对方已完全理解
●表达你对当事人仍然充满信任与信心
表扬进步
发现他们越做越好,即便做得不是完全正确,也要表扬他们的进步。通过这种方法,
你就将他们推上了成功之路,并使他们可以在那里继续前进
鲸鱼哲学反应
●立即表扬别人
●具体指出他们哪些做得对,哪些做得基本正确
●与他们分享你对于他们所做工作的积极感觉
●鼓励他们继续好好工作
猫捉老鼠
发现别人做的错事
鲸鱼哲学
发现别人做得正确的事情
当一切进展顺利的时候,
清醒点,
说点表示肯定的话!
无论什么时候,只要你批评了别人的行为或是给了对方一个否定的反馈,不管你多么
小心地去措辞,结果都会破坏或削弱你与他之间的关系。如果你不断地这样做,你就会彻底毁了这种关系。他们会对你失去信任并开始用同样的方法对待你。
首先,不需要被其他人激励而做事情的人只有企业家,他们要么拥有自己的生意,要么是为自己工作的自由职业者。他们是自觉的,而且他们的目标与整个组织的目标是联系在一起的。事实上,他们个人的目标通常与组织的目标是相同的。其他任何人——雇员、家里的孩子,或者是海洋世界的鲸鱼——被要求做的事情都是组织需要他们去做的事情,而且是那些如果让他们自己选择,他们可能会选择不做的事情。
即使是鲸鱼哲学反应本身也不是最终目的,它只是帮助人们实现‘发现自己做得正确的事情’这一最终目标的手段。
拥有权利是一件了不起的事情,但是不要利用它。你能够真正让人们做你想让他们做的事情的惟一途径,就是与他们建立起一种积极的、信任的关系。对人要及时肯定,这样你就会得到积极的结果。
如今,任何新的经营举措,不论是技术还是服务的革新,抑或是价格战略,都会立刻被别人知晓并被
抄袭。也就是说,你仅有的、真正可竞争的空间只是你与员工的关系。如果他们信任、尊重你,并相信你制定的目标,他们就会想方设法去取悦你的顾客。一旦你拥有了这些,再加上你的一些其他优势,比如产品质量、价格和市场营销以及送货上门等等,那就没有人能够战胜你了。你与下属的关系,以及下属与顾客之间的关系,任何竞争对手都永远无法从你这里偷走,只有这一样东西是你惟一拥有的。
规则就是,永远不要以为你知道可以激励别人的东西是什么。
鲸鱼哲学只有在你
真诚和诚实的时候才会奏效
一些“鲸鱼哲学”反应
在工作中
对管理人员:
你在会上提出的建议十分出色。你设计的开场白是为了引起人们的注意,我果然看到A女士在你说到XX的时候,神情很振奋。你在那么短的时间内所做的一切非常有助于客户对我们树立信心。你的话给我们所有人都增了光。继续好好干吧!
对一个工作团队:
咱们这个组在融洽合作与履行责任方面都非常出色。在接任本组的领导工作期间,是你们帮助我转换了
角色,让我从老板变成了协调人。我更喜欢这样的角色。希望我们这个团队继续好好工作。
对一个做出贡献的个人:
我很欣赏你在报告中自创的数字分组的方式,这样更容易看清结果。我想推荐所有人从现在开始都使用
你的方法。期待你今后想出更多的好主意。
对十几岁的儿子:
我真高兴回家看到你把车库打扫干净了。我原打算这个周六自己干这活儿,没想到你提前做了。这下我
可以放松放松,干点别的了。你让我松了口气,巴德,非常感谢你!
对一个刚上一年级的孩子:
早上我刚叫你一遍你就起床了。当时我们都在忙着收拾东西各自上路,你知道你一叫就起帮了我多少忙
吗?非常多!
对一个十二岁的女儿:
我非常喜欢在开车送你去运动和上课的路上跟你聊天。听你说你和你朋友们的事情真有趣。我希望在你
成长的过程中我们还能继续这样的交谈。
对一个学龄前儿童:
你没用别人帮忙就自己系好了鞋带、选好了要穿的衣服,真是棒极了!继续努力。我真为你感到骄傲。
一些调整指令反应
在工作中
●比尔,我知道你在使用新的结算系统时遇到了麻烦,我准备让贝蒂帮你一把。(一段时间后)干得不
错,比尔。你交上来的报告说明你在使用这套系统方面已经成了佼佼者。如果你有什么问题尽管告诉我。
●我们希望在这个项目上,每个人的才干都可以最大限度地发挥出来,埃利森。这就是我把你派到乔治
那一组去的原因。在那里,他们会用上你所有的技术。(一段时间后)祝贺你,埃利森。我早就知道你是跟乔治那一组工作的最佳人选。我非常欣赏你的工作。
在家里
(孩子没有好好喂宠物。)
我现在不让你喂宠物了,去用吸尘器打扫卫生吧。我知道你喜欢做这项家务,而且房间也确实该打扫了。(一段时间后)经过你的打扫,这房子看起来真漂亮!
(孩子们正在因为看电视而吵闹。)
为了让每个人都满意,我们需要为看电视制定一个计划。(一段时间后)我真高兴你们两个能按照那天
我们在厨房里制定的计划看电视!
posted @
2005-08-17 14:06 Dave 阅读(1310) |
评论 (2) |
编辑 收藏
Reflection combines with effective object-oriented design to allow programs to be more flexible. Delegation is useful because it allows an object to change behavior at runtime. This change in behavior happens when one delegate that provides one behavior is replaced with another delegate that provides a different behavior. The number of different delegates available defines the amount that this behavior can vary.
Without reflective mechanisms, the number of delegates is limited to only the set of classes that are included in the system at comple time. Reflection increases this range of variation by allowing the system to use classes that are written later. There are several noteworthy aspects of this relationship:
posted @
2005-08-17 10:41 Dave 阅读(89) |
评论 (0) |
编辑 收藏
public class MainApplication {
private Properties props;
private CustomerDatabase custDB;
public synchronized CustomerDatabase createDBFacade() {
if (custDB == null) {
try {
String dbClassName = props.getProperty("db.class",
"com.wci.app.StubCustomerDB");
Class cls = Class.forName(dbClassName);
custDB = (CustomerDatabase) cls.newInstance();
} catch (ClassNotFoundException ex) {
// ...
} catch (InstantiationException ex) {
// ...
} catch (IllegalAccessException ex) {
// ...
}
}
return custDB;
}
}
posted @
2005-08-17 10:11 Dave 阅读(96) |
评论 (0) |
编辑 收藏
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.Map;
import org.jdom.Document;
import org.jdom.Element;
public class Driver {
public static Document serializeObject(Object source) throws Exception {
return serializeHelper(source, new Document(new Element("serialized")),
new IdentityHashMap());
}
private static Document serializeHelper(Object source, Document target,
Map table) throws Exception {
String id = Integer.toString(table.size());
table.put(source, id);
Class sourceclass = source.getClass();
Element oElt = new Element("object");
oElt.setAttribute("class", sourceclass.getName());
oElt.setAttribute("id", id);
target.getRootElement().addContent(oElt);
if (!sourceclass.isArray()) {
Field[] fields = Mopex.getInstanceVariables(sourceclass);
for (int i = 0; i < fields.length; i++) {
if (!Modifier.isPublic(fields[i].getModifiers()))
fields[i].setAccessible(true);
Element fElt = new Element("field");
fElt.setAttribute("name", fields[i].getName());
Class declClass = fields[i].getDeclaringClass();
fElt.setAttribute("declaringclass", declClass.getName());
Class fieldtype = fields[i].getType();
Object child = fields[i].get(source);
if (Modifier.isTransient(fields[i].getModifiers())) {
child = null;
}
fElt.addContent(serializeVariable(fieldtype, child, target,
table));
oElt.addContent(fElt);
}
} else {
Class componentType = sourceclass.getComponentType();
int length = Array.getLength(source);
oElt.setAttribute("length", Integer.toString(length));
for (int i = 0; i < length; i++) {
oElt.addContent(serializeVariable(componentType, Array.get(
source, i), target, table));
}
}
return target;
}
private static Element serializeVariable(Class fieldtype, Object child,
Document target, Map table) throws Exception {
if (child == null) {
return new Element("null");
} else if (!fieldtype.isPrimitive()) {
Element reference = new Element("reference");
if (table.containsKey(child)) {
reference.setText(table.get(child).toString());
} else {
reference.setText(Integer.toString(table.size()));
serializeHelper(child, target, table);
}
return reference;
} else {
Element value = new Element("value");
value.setText(child.toString());
return value;
}
}
}
===============================
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;
public class Mopex {
public static Method getSupportedMethod(Class cls, String name,
Class[] paramTypes) throws NoSuchMethodException {
if (cls == null) {
throw new NoSuchMethodException();
}
try {
return cls.getDeclaredMethod(name, paramTypes);
} catch (NoSuchMethodException ex) {
return getSupportedMethod(cls.getSuperclass(), name, paramTypes);
}
}
public static Field[] getInstanceVariables(Class cls) {
List accum = new LinkedList();
while (cls != null) {
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (!Modifier.isStatic(fields[i].getModifiers())) {
if (!Modifier.isPublic(fields[i].getModifiers()))
fields[i].setAccessible(true);
accum.add(fields[i]);
}
}
cls = cls.getSuperclass();
}
Field[] retvalue = new Field[accum.size()];
return (Field[]) accum.toArray(retvalue);
}
}
===============================
public class Animal {
private String name;
private String gender;
private String classification;
private int weight;
public Animal(String name,String gender, String classification, int weight) {
super();
this.classification = classification;
this.gender = gender;
this.name = name;
this.weight = weight;
}
}
==============================
import java.util.ArrayList;
import java.util.List;
public class Zoo {
private String city;
private String name;
public Zoo(String name, String city) {
this.city = city;
this.name = name;
}
List animals = new ArrayList();
public void add(Animal panda1) {
animals.add(animals);
}
}
=========================
import org.jdom.Document;
import org.jdom.output.XMLOutputter;
public class ZooTest {
public static void main(String[] args) {
Animal panda1 = new Animal("Tian Tian", "male",
"Ailuropoda melanoleuca", 271);
Animal panda2 = new Animal("Mei Xiang", "female",
"Ailuropoda melanoleuca", 221);
Zoo national = new Zoo("National Zoological Park", "Washington, D.C.");
national.add(panda1);
national.add(panda2);
try {
XMLOutputter out = new XMLOutputter();
Document d = Driver.serializeObject(national);
out.output(d, System.out);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
posted @
2005-08-17 09:35 Dave 阅读(160) |
评论 (0) |
编辑 收藏
想在企業階梯中順利地一階一階往上爬?「今日管理」(Management Today)
雜誌日前指出,工作者應該注意幾個獲得升遷的秘訣:
1.願意多做一些。願意主動多做一些工作,可以贏得同事的感激,也顯示
了你已經準備好承擔更多的工作職責。
2.積極建立人際網路。無論公司內外,你認識的人越多,獲得新職務的機
會就越大。
3.執行深入細節,但是看法擴及整體。讓別人覺得你會思考公司的重要議
題,謹慎選擇適合的議題,表達你對該議題的看法。
4.熱情具有傳染性。展現出你對公司的熱情及忠誠,如果你的活力可以影
響其他人,公司會希望讓你扮演更重要的角色。
5.協助會議更順利進行。在會議中發揮助攻效果,顯示出你的獨特之處,
並且與別人建立更好的關係。
6.避免一般的事業生涯發展途徑。明天的領導人需要的經驗,可能與今天
的領導人不同,特別的事業生涯發展經歷,可以讓你在同事中鶴立雞群。
7.幾年更改一次職責。讓你保持對工作的新鮮感,也給予你更廣博的經驗
,增加競爭力。
8.有焦點,但也具彈性。決定自己想要的職務,想要的工作技能,以及你
將如何獲得它們,目標明確,但是也願意接受出現的新機會。
posted @
2005-08-16 09:30 Dave 阅读(97) |
评论 (0) |
编辑 收藏