论坛首页 Java企业应用论坛

矛盾:充血的领域模型和Web服务器装载的spring context

浏览 12739 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (7) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-01-06  
czx566 写道
的确我觉得我表达的能力还有所欠缺~
我准备写4,再补充论证这个问题。

我主题的意思是:
   任何一个软件系统,其实都应该包含了 过程和对象 两个部分。
   一般来说我们应该用service层代码实现过程逻辑,而领域对象则实现对象部分。
   那么对象的管理,一般来说我认为交给IOC去管理,是非常合适的。
   为什么?
   对于对象的调用者来说(即过程代码),对象怎么组成的,这个对象背后是否
   依赖其它对象或则环境,是不应该去关注和关心的,所以我们事例化一个对象
   都应该通过一个工厂去取得,而对象背后之间的关系,我们应该完全交给IOC
   来建立。这个和我过程代码无关。

    当然我们也可以将service层的代码 也归纳为一个对象,那我当然也可以将这
   个对象交给IOC去管理,这样就是IOC无边界的一种应用。那么会出现什么情况
   了?
    第一 我在编排IoC的配置文件时(即spring的xml文件),那么此配置文件是
   和你的过程逻辑有较强的耦合度的。就如同我例举的,我编写的明明是商场的配
   置,但我却要关心,这个主板商家在那里等等,如果有一天还出一个卖冰棍的,那
   不更莫名了?
    第二 不够OO;   
    当然,上面的理由总的说起来也无关大局~除非你有完美主义的倾向,呵呵
   
   所以我认为在service层 以上,过程逻辑 更普遍的时候,不应该用IOC.
   而只有到了领域模型以下,这个完全符合OO的层次,IOC才用得有意义.
  







我明白了你的意思。

对于service中的过程化的业务逻辑来说,他们需要操纵领域Bean,这时领域Bean对业务逻辑来说,属于召之即来,呼之即去的非长期依赖的对象,而IOC无论是setter方法还是构造器方法注入的都是类的成员变量类型的领域Bean,同service类具有相同的生民周期,自然显得多余了。所以,在service类中使用工厂模式或new的方法 在过程中 创建领域Bean更为合适。

而对于领域Bean中的DAO来说,只要领域Bean一出现,他就依赖于DAO,领域Bean死了DAO还不会死,因为DAO属于基础设施(所以用单例的方式存在),因此用IOC注入的方式比较合适。

这是我的理解。呵呵。我觉得我目前也是这么做的。只不过我没有用工厂方式在service里创建领域Bean,而是用new。
0 请登录后投票
   发表时间:2009-01-06  
samm 写道
nfxu 写道
嗯。我说的往领域bean里注入session factory实际上是DAO,呵呵。

但是DAO同session factory一样,也是在application context里声明的,对他的引用只能是声明式的注入,无法在创建新领域bean的时候用代码显示的获得对DAO引用,这正是我面临的问题。

也可以这么说,如何在通过Web容器启动了application context后,在代码里取得对这个application context的引用?就像这样:
DomainBean myBean = applicationContext.getBean("domainBean");




千万不要在一个应用建两个context啊,是可以拿的,其实不过是application context是存在application里面的。

方式1
-----------spring 文档------------------

3.5.2.1.  BeanFactoryAware
对于实现了org.springframework.beans.factory.BeanFactoryAware接口的类,当它被BeanFactory创建后,它会拥有一个指向创建它的BeanFactory的引用。

----------^_^强大的分割线^_^--------------

方式2,但好很强大。
WebApplicationContext  wac = WebApplicationContextUtils.getWebApplicationContext(
servletConfig.getServletContext());

很简单,传个参数就可以了。如果觉得传参很麻烦,写个filter或servlet初始一个Util类就OK了(在spring初始化之后)

创建新领域bean,这个无从谈起,一个单例Bean不救OK了吗?

不过充血模型是不依赖持久层框架的,你所说的更象ALL-IN-ONE形式。




谢谢你的建议。方式一我看懂了,方式二不是很明白。但我不打算采用方式一,因为显得比较复杂,我目前可能处理的不会很好。我还是倾向于这样,用web.xml启动一个application context,用来注入struts的actions,再用Bean factory的方式启动一个Bean factory,用来往service里注入DAO,往DAO里注入session factory,而在领域Bean里从这个factory里得到DAO(就不是注入了)。

我这样做可能有风险,但目前项目规模很小,除了问题重构起来还是很快的,也算是学习的一个过程。你的方法我打算收藏了,万一我的笨办法有问题,再用你的。
0 请登录后投票
   发表时间:2009-01-06  
lgx522 写道
这个所谓“贫血”、“充血”之论,大家其实没必要当真,扯来扯去,搞成经院式的空洞辩论了。
世间事本无“一招仙”的解决方法,如此在意“招式”是很无聊的。

国内搞Java和Spring的,大凡有点熟的,好像总喜欢扯点这类问题,好像挺有“深度”,其实是浪费时间精力。就算大家把MF的“模式”都搞清楚了,就真能解决一切问题了吗?不如学一学.NET、PHP和RoR,低头做点实事。Java世界不是用来折腾说事的,有能耐的,多写点有用的jar做开源才是要紧。


我的看法恰恰与你的相反~
我认为中国的软件界就是跟风太快~
功利心太强。
什么都搞,什么都不精通
最后永远只能跟着老外的屁股后面~
说白了,好像什么都会,但实际问得深入一点,反而就茫然了。




0 请登录后投票
   发表时间:2009-01-06  
nfxu 写道
情况是这样的:

1 一个架构为struts2,spring,hibernate的web应用。
2 采用充血的领域模型,即领域bean里含有一些简单的业务逻辑,例如CRUD之类的操作。这些操作需要hibernate的session factory以便访问数据库。
3 Spring中定义了session factory,因此可以将它注入任何需要的地方。同样也可以注入领域bean和service类中。

但问题是领域bean因为比较小(其实也不小,如果充血的话),一般用new的方式生成,因此无法从Spring中获得session factory。像service类比较大,一般是从Spring中获得实例,因此注入了session factory,没有问题。

如果是失血模型的话,领域类里只有getter 和setter方法,因此不存在注入session factory的问题。

当然我也可以用BeanFactory.getBean("beanName")的方式获得session factory,但这样就不够好看了,出现了applicationContext和BeanFactory并存的局面,感觉不优雅( 我现在的Spring是通过web.xml在Web服务器启动时载入的,因此是application context)。

难道大家不用充血模型?

在Spring reference的3.9. Glue code and the evil singleton中,似乎有些提示,但不怎么明白。


我认为CRUD这些操作不应该写在domain object里面,事实上CRUD也不属于domain logic范畴,只要在domain object中将状态修改好即可。实现上可以在application层进行事务提交控制(这些可以有AOP或Spring interceptor来做),一般来说这种是针对已持久化的对象的操作;对于新增的对象可以有Repository来完成。
0 请登录后投票
   发表时间:2009-01-06  
nfxu 写道
samm 写道
nfxu 写道
嗯。我说的往领域bean里注入session factory实际上是DAO,呵呵。

但是DAO同session factory一样,也是在application context里声明的,对他的引用只能是声明式的注入,无法在创建新领域bean的时候用代码显示的获得对DAO引用,这正是我面临的问题。

也可以这么说,如何在通过Web容器启动了application context后,在代码里取得对这个application context的引用?就像这样:
DomainBean myBean = applicationContext.getBean("domainBean");




千万不要在一个应用建两个context啊,是可以拿的,其实不过是application context是存在application里面的。

方式1
-----------spring 文档------------------

3.5.2.1.  BeanFactoryAware
对于实现了org.springframework.beans.factory.BeanFactoryAware接口的类,当它被BeanFactory创建后,它会拥有一个指向创建它的BeanFactory的引用。

----------^_^强大的分割线^_^--------------

方式2,但好很强大。
WebApplicationContext  wac = WebApplicationContextUtils.getWebApplicationContext(
servletConfig.getServletContext());

很简单,传个参数就可以了。如果觉得传参很麻烦,写个filter或servlet初始一个Util类就OK了(在spring初始化之后)

创建新领域bean,这个无从谈起,一个单例Bean不救OK了吗?

不过充血模型是不依赖持久层框架的,你所说的更象ALL-IN-ONE形式。




谢谢你的建议。方式一我看懂了,方式二不是很明白。但我不打算采用方式一,因为显得比较复杂,我目前可能处理的不会很好。我还是倾向于这样,用web.xml启动一个application context,用来注入struts的actions,再用Bean factory的方式启动一个Bean factory,用来往service里注入DAO,往DAO里注入session factory,而在领域Bean里从这个factory里得到DAO(就不是注入了)。

我这样做可能有风险,但目前项目规模很小,除了问题重构起来还是很快的,也算是学习的一个过程。你的方法我打算收藏了,万一我的笨办法有问题,再用你的。




这个是不是说你的应用里存在两个Bean factory呢?这个不好,事务控制可能无效,资源浪费!
方式2再说说。
说白了,application context无非是保存在application(请不要说这个不知道哦,jsp默认下提供的东东,filter 的init(FilterConfig arg0)方法中arg0.getServletContext()这样得到)中的变量。

这个变量是怎么来的呢? 请看下面的配置项。默认情况下,在这个listener中application.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,applicationcontext);

<listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


WebApplicationContextUtils 这个是spring提供的工具类。
0 请登录后投票
   发表时间:2009-01-07  
实施证明,充血模型是Martin大叔的失败的理论之一
JPA/EJB3要是用充血模型,甚至涨血模型,那就死定了
lz不要在域模型这上面费心思,域模型还是POJO最好用

再说了,其实持久化等功能本来从OO角度来看也不是域模型的职责
你这个架构实在是太别扭了

另外,IoC是有边界的,哪些bean需要从IoC获得,哪些需要new,哪些需要用factory/builder等pattern创建,这个要看具体架构需求。就域模型来说,new一下就可以了,除非你要spring cglib做aop
0 请登录后投票
   发表时间:2009-01-07  
框架限制使你难于实现,可考察一下其它框架。
0 请登录后投票
   发表时间:2009-01-07  
所以可以直接在ServletContext取出WebApplicationContext 对象:

WebApplicationContext webApplicationContext = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

0 请登录后投票
   发表时间:2009-01-07  
DanielYWoo 写道
实施证明,充血模型是Martin大叔的失败的理论之一
JPA/EJB3要是用充血模型,甚至涨血模型,那就死定了
lz不要在域模型这上面费心思,域模型还是POJO最好用

再说了,其实持久化等功能本来从OO角度来看也不是域模型的职责
你这个架构实在是太别扭了

另外,IoC是有边界的,哪些bean需要从IoC获得,哪些需要new,哪些需要用factory/builder等pattern创建,这个要看具体架构需求。就域模型来说,new一下就可以了,除非你要spring cglib做aop



很想听听 你上面所说的实施证明

因为对于领域模型 我接触的时间还是比较短,
不过当我接触到领域模型的理论了后,我还是认为这应该是一条光明大道

我现在做的项目我准备推行领域模型,至少是充血,甚至涨血也有可能。
因为我觉得随着java语言对动态语言的支持度的提高,涨血可能是最终的归途!
0 请登录后投票
   发表时间:2009-01-07  
斑竹就是想问一下不用new 如何得到spring容器,你们说了4个分页到底在说什么呢。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics