愛因斯坦曾經說:“任何事情都應該越簡單越好,而不是比較簡單。”實際上,科學真理的目的就是在假設的前提下去簡化一個理論,這樣,人們可以去關注真正重要的問題。在企業軟件開發中,道理是一樣的。
簡化企業軟件開發的一個關鍵是,提供一個這樣的應用框架:它可以使開發人員不用關注于很多復雜的問題,比如事務處理、安全和持久化等。一個設計良好的框架將提升代碼的可復用性,提高開發者的效率,并得到更高質量的軟件。然而,目前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 閱讀(227) |
評論 (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 閱讀(1208) |
評論 (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 閱讀(914) |
評論 (2) |
編輯 收藏
投資是一種追求未來貨幣增值的經濟行為。
新中國的第一張股票:1984年12月發行的上海飛樂音響公司的股票。
90年12月19日,上證交易所開業
posted @
2005-08-19 15:36 Dave 閱讀(156) |
評論 (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 閱讀(201) |
評論 (0) |
編輯 收藏
建立信任
及時給予肯定
出錯時調整注意力
表現管理學ABC
A=催化劑(activator)
任何引發表現的原因
B=行為(behavior)
發生的表現
C=結果(consequence)
你對所產生表現的反應
四種結果
1.沒有反應
2.表示否定
3.調整指令
4.表示肯定
調整指令的方法
●盡可能快地、清晰而不帶責備地指出錯誤
●解釋錯誤的負面影響
●如果可以,將過錯歸結于沒有清楚地解釋工作任務
●詳細地重新解釋工作任務,并確保對方已完全理解
●表達你對當事人仍然充滿信任與信心
表揚進步
發現他們越做越好,即便做得不是完全正確,也要表揚他們的進步。通過這種方法,
你就將他們推上了成功之路,并使他們可以在那里繼續前進
鯨魚哲學反應
●立即表揚別人
●具體指出他們哪些做得對,哪些做得基本正確
●與他們分享你對于他們所做工作的積極感覺
●鼓勵他們繼續好好工作
貓捉老鼠
發現別人做的錯事
鯨魚哲學
發現別人做得正確的事情
當一切進展順利的時候,
清醒點,
說點表示肯定的話!
無論什么時候,只要你批評了別人的行為或是給了對方一個否定的反饋,不管你多么
小心地去措辭,結果都會破壞或削弱你與他之間的關系。如果你不斷地這樣做,你就會徹底毀了這種關系。他們會對你失去信任并開始用同樣的方法對待你。
首先,不需要被其他人激勵而做事情的人只有企業家,他們要么擁有自己的生意,要么是為自己工作的自由職業者。他們是自覺的,而且他們的目標與整個組織的目標是聯系在一起的。事實上,他們個人的目標通常與組織的目標是相同的。其他任何人——雇員、家里的孩子,或者是海洋世界的鯨魚——被要求做的事情都是組織需要他們去做的事情,而且是那些如果讓他們自己選擇,他們可能會選擇不做的事情。
即使是鯨魚哲學反應本身也不是最終目的,它只是幫助人們實現‘發現自己做得正確的事情’這一最終目標的手段。
擁有權利是一件了不起的事情,但是不要利用它。你能夠真正讓人們做你想讓他們做的事情的惟一途徑,就是與他們建立起一種積極的、信任的關系。對人要及時肯定,這樣你就會得到積極的結果。
如今,任何新的經營舉措,不論是技術還是服務的革新,抑或是價格戰略,都會立刻被別人知曉并被
抄襲。也就是說,你僅有的、真正可競爭的空間只是你與員工的關系。如果他們信任、尊重你,并相信你制定的目標,他們就會想方設法去取悅你的顧客。一旦你擁有了這些,再加上你的一些其他優勢,比如產品質量、價格和市場營銷以及送貨上門等等,那就沒有人能夠戰勝你了。你與下屬的關系,以及下屬與顧客之間的關系,任何競爭對手都永遠無法從你這里偷走,只有這一樣東西是你惟一擁有的。
規則就是,永遠不要以為你知道可以激勵別人的東西是什么。
鯨魚哲學只有在你
真誠和誠實的時候才會奏效
一些“鯨魚哲學”反應
在工作中
對管理人員:
你在會上提出的建議十分出色。你設計的開場白是為了引起人們的注意,我果然看到A女士在你說到XX的時候,神情很振奮。你在那么短的時間內所做的一切非常有助于客戶對我們樹立信心。你的話給我們所有人都增了光。繼續好好干吧!
對一個工作團隊:
咱們這個組在融洽合作與履行責任方面都非常出色。在接任本組的領導工作期間,是你們幫助我轉換了
角色,讓我從老板變成了協調人。我更喜歡這樣的角色。希望我們這個團隊繼續好好工作。
對一個做出貢獻的個人:
我很欣賞你在報告中自創的數字分組的方式,這樣更容易看清結果。我想推薦所有人從現在開始都使用
你的方法。期待你今后想出更多的好主意。
對十幾歲的兒子:
我真高興回家看到你把車庫打掃干凈了。我原打算這個周六自己干這活兒,沒想到你提前做了。這下我
可以放松放松,干點別的了。你讓我松了口氣,巴德,非常感謝你!
對一個剛上一年級的孩子:
早上我剛叫你一遍你就起床了。當時我們都在忙著收拾東西各自上路,你知道你一叫就起幫了我多少忙
嗎?非常多!
對一個十二歲的女兒:
我非常喜歡在開車送你去運動和上課的路上跟你聊天。聽你說你和你朋友們的事情真有趣。我希望在你
成長的過程中我們還能繼續這樣的交談。
對一個學齡前兒童:
你沒用別人幫忙就自己系好了鞋帶、選好了要穿的衣服,真是棒極了!繼續努力。我真為你感到驕傲。
一些調整指令反應
在工作中
●比爾,我知道你在使用新的結算系統時遇到了麻煩,我準備讓貝蒂幫你一把。(一段時間后)干得不
錯,比爾。你交上來的報告說明你在使用這套系統方面已經成了佼佼者。如果你有什么問題盡管告訴我。
●我們希望在這個項目上,每個人的才干都可以最大限度地發揮出來,埃利森。這就是我把你派到喬治
那一組去的原因。在那里,他們會用上你所有的技術。(一段時間后)祝賀你,埃利森。我早就知道你是跟喬治那一組工作的最佳人選。我非常欣賞你的工作。
在家里
(孩子沒有好好喂寵物。)
我現在不讓你喂寵物了,去用吸塵器打掃衛生吧。我知道你喜歡做這項家務,而且房間也確實該打掃了。(一段時間后)經過你的打掃,這房子看起來真漂亮!
(孩子們正在因為看電視而吵鬧。)
為了讓每個人都滿意,我們需要為看電視制定一個計劃。(一段時間后)我真高興你們兩個能按照那天
我們在廚房里制定的計劃看電視!
posted @
2005-08-17 14:06 Dave 閱讀(1314) |
評論 (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 閱讀(98) |
評論 (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 閱讀(162) |
評論 (0) |
編輯 收藏
想在企業階梯中順利地一階一階往上爬?「今日管理」(Management Today)
雜誌日前指出,工作者應該注意幾個獲得升遷的秘訣:
1.願意多做一些。願意主動多做一些工作,可以贏得同事的感激,也顯示
了你已經準備好承擔更多的工作職責。
2.積極建立人際網路。無論公司內外,你認識的人越多,獲得新職務的機
會就越大。
3.執行深入細節,但是看法擴及整體。讓別人覺得你會思考公司的重要議
題,謹慎選擇適合的議題,表達你對該議題的看法。
4.熱情具有傳染性。展現出你對公司的熱情及忠誠,如果你的活力可以影
響其他人,公司會希望讓你扮演更重要的角色。
5.協助會議更順利進行。在會議中發揮助攻效果,顯示出你的獨特之處,
並且與別人建立更好的關係。
6.避免一般的事業生涯發展途徑。明天的領導人需要的經驗,可能與今天
的領導人不同,特別的事業生涯發展經歷,可以讓你在同事中鶴立雞群。
7.幾年更改一次職責。讓你保持對工作的新鮮感,也給予你更廣博的經驗
,增加競爭力。
8.有焦點,但也具彈性。決定自己想要的職務,想要的工作技能,以及你
將如何獲得它們,目標明確,但是也願意接受出現的新機會。
posted @
2005-08-16 09:30 Dave 閱讀(100) |
評論 (0) |
編輯 收藏