贴seam文档,似曾相识!

最近注意了一下seam文档,牛人Gavin King的观点貌似好多都曾出现在jdon,在jdon上混得久的人也许早就注意到了,下面贴文档的一部分:

有状态Session Bean不仅可以在bean的多次调用之间保持状态,而且在多次请求之间也可以保持状态。 不由数据库保存的状态通常应该由有状态Session Bean保持。这是Seam和其他web框架之间的一个显著的不同点。 其他框架把当前会话的信息直接保存在 HttpSession 中,而在Seam中你应该把它们保存在有状态Session Bean的实例中,该实例被绑定到会话上下文。这可以让Seam来替你管理状态的生命周期,并且保证在多个不同的并发会话中没有状态冲突。


Seam是从Hibernate团队试图生成典型的无状态Java应用架构的挫折中成长起来的。 上一代Java应用程序的无状态特性让Hibernate团队饱受挫折,Seam吸取了他们的经验。 Seam的状态管理架构最早是用来解决持久化冲突相关问题的,特别是 乐观事务处理 相关的问题。可扩展的在线应用经常使用乐观事务。 一个原子(database/JTA)级的事务不应该跨用户交互,除非系统设计时就是只支撑很少量的并发客户端。 但几乎所有涉及到的工作都是先将数据展现给用户,没多久后更新这个数据。所以Hibernate是依据支持一种跨乐观事务的持久化上下文的思想设计的。

不幸的是这个先于Seam和EJB3.0出现的所谓“无状态”架构并不对乐观事务进行支持。而相反,这些架构提供对于原子事务级的持久化上下文的支持。 这当然给用户带来了很多麻烦,这也是用户抱怨排名第一的Hibernate的 LazyInitializationException 问题的原因。 我们需要的是在应用层构建对于乐观事务的支持。

EJB3.0认识到了此问题,并且也引入了有状态组件(有状态会话bean)的思想,它使用一个 扩展持久化上下文来跟踪组件的生命周期。 这是该问题的部分解决方案(对它自身而言也是一个有用的构想),然而还有两个问题:

有状态会话bean的生命周期必须在Web层通过代码手动管理(这是个麻烦的问题,而且实践起来比听上去更复杂)。

在同一个乐观事务的不同有状态组件间,传播持久化上下文是可行的,但很困难。

Seam通过提供对话(Conversation)和对话期间的有状态Session Bean组件来解决第一个问题(大多数会话实际上在数据层支持乐观事务)。 这对于很多不需要传递持久化上下文的简单应用(比如Seam的订阅演示程序)已经足够了。 对于更复杂的在每一个对话中的有很多松耦合组件的应用来说,组件间传播持久化上下文就成为一个重要的问题了。 所以Seam扩展了EJB 3.0的持久化上下文管理模型,以此来提供对话作用域的扩展持久化上下文。

数据库成为了大多数企业应用的主要瓶颈,也成为了运行环境中最不具伸缩性的层。PHP/Ruby的用户会说什么都不共享(share nothing)的架构照样具有很好的伸缩性。从表面上看也许是对的,可惜我不知道是否存在这样的多用户应用,其实现是能够在集群的不同结点间不共享资源。这些傻瓜真正想的是“除了数据库以外什么都不共享(Share nothing except for the database)”的架构。当然,共享数据库是多用户应用伸缩性的主要问题——因此声称这样的架构具有高伸缩性是荒谬的,你可要知道它们花费了这些人的大部分时间。

通常,几乎所有通过共享数据库做的事情并不值得这样去做。

这就是缓存(Cache)产生的原因。嗯,当然并不只是一个缓存。一个设计良好的Seam应用将具有丰富的多层缓存策略,这也影响着应用的每一层:

当然,数据库有它自己的缓存,这是超级重要的,但是它不能像应用层的缓存一样具有伸缩性。

对从数据库提取出的数据,你的ORM解决方案(Hibernate,或者别的JPA实现)具有两级缓存。这是一种很强大的能力,但是经常被误用。在一个集群环境里,保持缓存中的数据在整个集群中具有事务一致性,并且和数据库一致,其代价是相当昂贵的。这对于共享在多个用户间,且很少被更新的数据最有意义。在传统的无状态架构里,人们经常使用二级缓存来保存会话状态。这种做法总是糟糕的,在Seam中更是大错特错的。

Seam会话上下文是会话状态的缓存。存储于会话上下文中的组件可以保持并缓存与当前用户交互相关的状态。

特别的,Seam管理的持久化上下文(或者一个扩展受管EJB容器持久化上下文,它与会话范围的无状态会话Bean相关)成为了当前会话中数据的缓存。这种缓存趋向于拥有一个相当高的命中率!Seam优化了集群环境中受管Seam持久化上下文的复制,也不需要保证数据库事务的一致性(乐观锁已足够),因此你不必担心这种缓存的性能问题,除非你把成千上万个对象读取到一个单独的持久化上下文中。

应用可以在Seam应用上下文中缓存非事务性状态。相应的,保存在应用上下文中的状态不能被集群中其它结点访问。

应用通过Seam的 pojoCache 组件可以缓存事务性状态,这个组件把JBossCache集成到了Seam环境中。如果你在集群模式下运行了JBossCache,那么这个状态是可以被别的结点访问的。

最后,Seam让你能够缓存生成的JSF页面的部分内容(rendered fragments)。与ORM的二级缓存不一样的是,当数据发生变化时,这种缓存不能自动的失效,因此你需要写应用代码来使它显式的失效,或者设置适当的过期策略。

如要获得更多关于二级缓存的信息,你可以参考你的ORM解决方案的文档,因为这是个极为复杂的话题。在这节中我们会直接讨论通过 pojoCache 组件使用JBossCache,或者通过 <s:cache>控制充当页片段(page fragment)缓存。

EJB会话Bean有声明式事务管理功能。当Bean被调用时,EJB容器能够透明地开始一个事务,在调用结束时关闭此事务。 如果我们写了一个作为JSF动作监听器的会话Bean方法,我们就可以在一个事务内处理所有与此action相关的工作,并且当我们完成此动作处理时事务必须被提交或回滚。 这是一个很棒的功能,在很多Seam应用程序中这是必需的。

但是,此方法还是有问题。Seam应用可能无法在对会话Bean的一次方法调用请求中完成所有的数据访问。

此请求可能由几个松耦合组件处理,Web层独立地调用每一个组件。在Seam中,Web层的一个请求对EJB组件发起几次甚至多次调用的现象是很常见的。

视图渲染可能需要延迟关联获取(lazy fetching of associations)。

每个请求的事务量越多,当我们的应用处理大量并发请求时越可能碰到原子和隔离问题。当然,所有的写操作要在一个事务中执行。

Hibernate用户开发了 "Open Session in View" 模式来解决该问题。 在Hibernate社区,"Open Session in View"曾经非常重要,这是因为像Spring这样的框架使用了事务作用域持久化上下文。 所以当未获得的关联被访问时渲染视图将引起 LazyInitializationException 异常。

这个模式通常作为一个跨越整个请求的事务来实现。 此实现方式会有几个问题,其中最严重的是只有我们提交了事务才能确认它成功完成——但在"Open Session in View"的事务提交时,视图已经完全渲染了,甚至渲染好的应答可能已经刷新到客户端。我们怎样才能通知用户他们的事务已失败呢?

Seam在解决"Open Session in View"问题时,也解决了事务隔离和关联获取问题。该方案有有两个部分:

使用使用已扩展持久化上下文,可以覆盖一个会话作用域而不是单个事务作用域。

每次请求使用两个事务;第一个从更新模型值的起始阶段到应用程序调用结束;第二个跨越渲染响应阶段。

很多应用服务器的 HttpSession 集群实现都有问题,对绑定到Session的可变对象状态的改变只有在明确调用 setAttribute() 的时候才会被复制。 这是Bug的一个源头,这些Bug难以在开发阶段有效找出,因为它们只会在应用服务器失效切换的时候才会被发现。 而且,实际的复制信息包含了绑定到Session的所有序列化对象图,这是低效的。
当然,EJB 有状态Session Bean必须进行自动dirty checking,并进行可变状态的复制,并且EJB 容器也应该引入优化,例如属性级别的复制。 但不幸的是,并非所有的Seam用户都有这么好的运气,他们的环境可能并不支持EJB 3.0。 因此,对于Session和Conversation范围内的JavaBean和Entity Bean组件,在Web容器的Session集群之上,Seam提供了额外的集群安全的状态管理层。

让我佩服的是Gavin King说出了这样的话:

数据库成为了大多数企业应用的主要瓶颈,也成为了运行环境中最不具伸缩性的层。PHP/Ruby的用户会说什么都不共享(share nothing)的架构照样具有很好的伸缩性。从表面上看也许是对的,可惜我不知道是否存在这样的多用户应用,其实现是能够在集群的不同结点间不共享资源。这些傻瓜真正想的是“除了数据库以外什么都不共享(Share nothing except for the database)”的架构。当然,共享数据库是多用户应用伸缩性的主要问题——因此声称这样的架构具有高伸缩性是荒谬的,你可要知道它们花费了这些人的大部分时间。

通常,几乎所有通过共享数据库做的事情并不值得这样去做。

>>Hibernate用户开发了 "Open Session in View" 模式来解决该问题。 在Hibernate社区,"Open Session in View"曾经非常重要,这是因为像Spring这样的框架使用了事务作用域持久化上下文。 所以当未获得的关联被访问时渲染视图将引起 LazyInitializationException 异常。

这个模式通常作为一个跨越整个请求的事务来实现。 此实现方式会有几个问题,其中最严重的是只有我们提交了事务才能确认它成功完成——但在"Open Session in View"的事务提交时,视图已经完全渲染了,甚至渲染好的应答可能已经刷新到客户端。我们怎样才能通知用户他们的事务已失败呢?

反模式Open Session in View在jdon的讨论帖不胜枚举,我们怎样才能通知用户他们的事务已失败呢?,也许jdon的解决方案更好,在持久层打开session,只在表现层检查开启与否。

>>不由数据库保存的状态通常应该由有状态Session Bean保持。这是Seam和其他web框架之间的一个显著的不同点。 其他框架把当前会话的信息直接保存在 HttpSession 中,而在Seam中你应该把它们保存在有状态Session Bean的实例中,该实例被绑定到会话上下文。这可以让Seam来替你管理状态的生命周期,并且保证在多个不同的并发会话中没有状态冲突。

其他框架把当前会话的信息直接保存在 HttpSession 中,Gavin King说这句话的时候应该让他知道在中国有一个JdonFrameWork.

>>这就是缓存(Cache)产生的原因。嗯,当然并不只是一个缓存。一个设计良好的Seam应用将具有丰富的多层缓存策略,这也影响着应用的每一层:
当然,数据库有它自己的缓存,这是超级重要的,但是它不能像应用层的缓存一样具有伸缩性。
对从数据库提取出的数据,你的ORM解决方案(Hibernate,或者别的JPA实现)具有两级缓存。这是一种很强大的能力,但是经常被误用。在一个集群环境里,保持缓存中的数据在整个集群中具有事务一致性,并且和数据库一致,其代价是相当昂贵的。这对于共享在多个用户间,且很少被更新的数据最有意义。在传统的无状态架构里,人们经常使用二级缓存来保存会话状态。这种做法总是糟糕的,在Seam中更是大错特错的.

在jdon,你发现了相同或者类似的观点了吗?

我最欣赏Gavin King的这句话,狠狠煽了那些曾经跟随Gavin King人的耳光:

数据库成为了大多数企业应用的主要瓶颈,也成为了运行环境中最不具伸缩性的层。
PHP/Ruby的用户会说什么都不共享(share nothing)的架构照样具有很好的伸缩性,这些傻瓜真正想的是“除了数据库以外什么都不共享(Share nothing except for the database)”的架构

我先来翻译一下上面这段意思:经过大量实践证明:数据库已经成为企业计算主要性能瓶颈,因为我们大量业务计算依赖数据库,虽然,数据库可以集群,但是代价昂贵,效率不高,而且最多两台或几台,因此,数据库已经成为运行环境中最不scalable的环节。

所谓伸缩性,就是弹性,整个软件架构既支持小负载运行,也支持大负载支持,只要增加服务器(PC服务器价格是便宜)即可;没有伸缩性意思这个软件小负载可以运行,到大负载,就有天花板了,即使进行数据库性能调优(这也是不少人觉得数据库技术很重要的原因),也只是缓口气,性能调优也有天花板,单台机器挖潜力总是有限的,向下死挖的概念就造成现在很多人对数据库调优技术的依赖;其实这些人为什么不向上想想,一台不够,我再增加一台,只要配置一下即可,经过权威测试:websphere/weblogic的20台PC服务器集群性能不亚于一台SUN/IBM的中型机,性价比已经一目了然了。

跟随PHP/Ruby的那些傻瓜用户认识到这点,就开始回避,宣称:share nothing,其实这是不可能的,应用中的很多数据都是依靠反复访问同一个数据库来达到共享,所以,实质是:Share nothing except for the database,类似鸵鸟把头插入沙子,认为就可以解决问题。

那么我们看看EJB或分布式缓存是如何解决这个共享问题:因为软件业务逻辑都是基于对象的,而这些对象可以在多台websphere/weblogic/jboss之间传输,通过分布式缓存就解决了共享问题,应用逻辑不必每次都要通过数据库来分享数据,应用逻辑之间本身可以直接传输业务对象数据,以达到分享。

所以,PHP/Ruby运行环境的架构特点还都是依赖数据库的,虽然他们打着Evans DDD口号,并且声称Ruby On Rails还是最适合DDD的,到时到最后落实代码时,就露出马脚,披着羊皮的狼,批着DDD,实则是以数据库中心。这也是为什么一些程序员既认为分析设计是要采取DDD,但是数据库技术依然重要的原因,这些都是不彻底的对象程序员,他们必然遭遇对象/关系数据库带来的复杂性,然后他们错以为是语言问题,转而追寻ROR这样动态语言,希望这个新语言能解救他们,虽然ROR有类似Hibernate之类ActiveRecord等ORM框架,由于运行环境还是依赖不伸缩的数据库,当系统复杂时,他们又会碰到oo/db的不匹配,真是傻瓜了。

当然,这种畸形也许适合一些中庸的中国程序员(对象和数据库两个都要)。不是我在大喊数据库时代过去时,那么多人反对,反对弱化数据库,因为他们脑子里数据库为王已经根深蒂固,就像一个保皇派,保数据库这个皇帝,大权不能旁落。

另外:我一直提出的Open Session In View是一个在Spring中无法解决的问题,是一个反模式,这点在Seam中也得到了解决,这说明是一个真理,我喜欢在Jdon说真话,很多言论都可以查询,2003年至今我没有发现严重的错误观点和预测,唯一没料到的是:PHP比我想象中顽强。

关于Seam更多讨论:

Gavin King真正走上EJB路线,推出基于JSF/EJB3的快速开发框架JBoss Seam :
http://www.jdon.com/jivejdon/thread/27279.html

翻译:JBoss Seam 2.0蹦达出来了
http://www.jdon.com/jivejdon/thread/32192.html

如何在EJB3.0架构下进行DDD实践?
http://www.jdon.com/jivejdon/thread/34514.html

更多Seam讨论:
http://www.jdon.com/jivejdon/query/searchThreadAction.shtml?query=Seam&view=on

数据库保皇派言论:
http://www.jdon.com/jivejdon/forum/messageList.shtml?thread=20162&message=23116346#23116346
[该贴被banq于2008-08-23 18:41修改过]
[该贴被banq于2008-08-24 10:26修改过]

个人觉得jdon框架可以在seam的方向上大胆再创新,包括ajax和有态管理,因为banq你早再04年的时候就把seam赢了,seam发展到现在依靠人多钱多而jdon却孤身仗剑!

>因为banq你早再04年的时候就把seam赢了
关键问题是:当时推出Jdon框架时,一些高手怀疑声一片,最主要的理由就是:国外没有类似框架,我坚称是国际新水平框架,他们笑了,BanQ总是说疯话。中国软件不行不是个人能力不行,是文化等其他非技术问题。

Jdon框架以后不会将Seam或任何一个现成作为目标,走自己的路,下一步引入元注释,都流行啊。

[该贴被banq于2008-08-25 11:15修改过]

呵呵,希望jdon框架真正能够流行起来。我觉得关键是资源太少了,无论是网上资源,还是书面的资源,希望banq老师出本书,讲述一下jdon框架,可以结合这个论坛来讲解。让更多的人了解这个框架。
[该贴被xmuzyu于2008-08-25 13:09修改过]

Banq如果在宣传方面加大力度,seam可能是由你来主持了.好的东西还是要更多人知道,用起来才行.开始还要点吹.就跟soa一样.

顶。好文 。例子呢


讲得不错 比较详细 了解seam必看

包括ajax 、有态管理、jsf、注解 希望jf走得更走!

In almost all enterprise applications, the database is the primary bottleneck, and the least scalable tier of the runtime environment. People from a PHP/Ruby environment will try to tell you that so-called "shared nothing" architectures scale well. While that may be literally true, I don't know of many interesting multi-user applications which can be implemented with no sharing of resources between different nodes of the cluster. What these silly people are really thinking of is a "share nothing except for the database" architecture. Of course, sharing the database is the primary problem with scaling a multi-user application—so the claim that this architecture is highly scalable is absurd, and tells you a lot about the kind of applications that these folks spend most of their time working on.

Almost anything we can possibly do to share the database less often is worth doing

这篇文章介绍MYSpace是怎么被数据库这个瓶颈不断折磨,滚滚爬爬的支撑到现在,还是有人抱怨资料丢失:
http://www.jdon.com/jivejdon/thread/34601.html

如果我们在架构之初就认识到数据库可能成为瓶颈,并从一开始就提供一个不依赖数据库本身的可伸缩的解决方案,何苦那么折腾呢? myspace直接得到微软SQLserver支持,都搞不定,何况你我,这也是为什么Oracle推JavaEE/EJB3非常起劲的原因了。