`
nfxu
  • 浏览: 4251 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

阅读更多
情况是这样的:

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中,似乎有些提示,但不怎么明白。
分享到:
评论
20 楼 nfxu 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。
19 楼 lgx522 2009-01-06  
这个所谓“贫血”、“充血”之论,大家其实没必要当真,扯来扯去,搞成经院式的空洞辩论了。
世间事本无“一招仙”的解决方法,如此在意“招式”是很无聊的。

国内搞Java和Spring的,大凡有点熟的,好像总喜欢扯点这类问题,好像挺有“深度”,其实是浪费时间精力。就算大家把MF的“模式”都搞清楚了,就真能解决一切问题了吗?不如学一学.NET、PHP和RoR,低头做点实事。Java世界不是用来折腾说事的,有能耐的,多写点有用的jar做开源才是要紧。
18 楼 czx566 2009-01-05  
的确我觉得我表达的能力还有所欠缺~
我准备写4,再补充论证这个问题。

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

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




17 楼 samm 2009-01-05  
创建新领域bean,这个无从谈起,一个单例Bean不救OK了吗?

这里错了

无法在创建新领域bean的时候用代码显示的获得对DAO引用,用一个非单例bean
16 楼 samm 2009-01-05  
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形式。

15 楼 nfxu 2009-01-05  
czx566 写道
交给spring管理没问题

但用IoC一杆子捅到底,这样做好么?

我持保留看法~


我看了你写的胡说系列,很好,对service和领域Bean的理解我很赞同。我准备收藏下来,回头再读读。

IOC和工厂模式之间的差别,dongwenhua已经表达了这个意思了,所以我就不多说了。我只是想起来一句话,关于IOC的,很有意思,对于对象及其依赖对象之间的关系,就像好莱坞电影里的对话一样,don't call me, i will call you.这是被依赖对象对依赖对象说的。呵呵。

如果考虑到领域Bean的生命周期实际上是由业务逻辑来控制的,那么,由Spring将领域Bean注入业务逻辑所在的service好不好呢?我觉得你的意思是说不好(电脑商城和主板,芯片商户的例子),可是你怎么又说IOC最好实现在领域模型里呢?这个我不是很明白。
14 楼 nfxu 2009-01-05  
不重复。

我的service里主要是处理领域Bean里不能处理的业务逻辑,就是比较大的,超过单个领域Bean范围的逻辑。比如列出一个list,就用service。所以service中也需要DAO。但service和DAO都是单例,所以很容易用Spring来管理。

多说一句,我在action和service之间实际上还有一层,专门用来读取action中传进来的request中的用户数据,组装好后,才交给service层。service层的调用完全采用的是JSE的类,没有和容器相关的类,如HTTP request等。这么做的结果是,我的service层及以下可以直接复用在一个用swing做界面的桌面系统里。
13 楼 nfxu 2009-01-05  
等我先看完你的胡说在说 呵呵
12 楼 czx566 2009-01-05  
交给spring管理没问题

但用IoC一杆子捅到底,这样做好么?

我持保留看法~
11 楼 nfxu 2009-01-05  
其实Spring管理的对象的生命周期的问题,我发帖子之前,一直没有意识到,只是在讨论中才明白过来。

把action交给Spring管理的原因是因为大家都在这么用,而我目前还是处于学习阶段,自然是有样学样啊。你看Spring的文档里,struts的文档里,都在说如何将struts和Spring集成起来,也就是将action交给Spring来管理。

我的分层里有service的。
10 楼 nfxu 2009-01-05  
spyker 写道
你说的单体是单例么?
spring中不是有多例的实现么?
不知道我理解的是不是这样

如果我理解正确的话 那你的那些问题不解决了么


对,我说的单体就是singleton。

对,Spring 中用prototype就可以得到多例。但对于我的领域对象(Bean),我不想交给Spring来管理,也就是说,我想用new的方式自己来管理,因为他们是有生命周期的,在service的逻辑处理完成后,需要被抛弃的。但Spring管理的对象都是单例(有一个例外,就是struts的action),生命周期同整个应用的生命周期一致。

为什么把action也交给Spring来管理呢?很简单,就是因为牛人们都这么做,我要是不这么做的话,岂不是太没品味啦?!
9 楼 nfxu 2009-01-05  
spyker 写道
我觉得你充血模型这块设置的有问题
从测试角度来说
这一块处理的一些业务应该不涉及到持久层这一块的

我觉得这一块应该是简单的一些逻辑处理
不引入其他层的对象

可以做单体测试的


嗯,我不会做单体测试,呵呵  

所以也不怎么往这方面想。但我的主要原则是:处理相同对象的逻辑要集中,关系相近,处理方式相近的逻辑要集中。尽量复用代码,尽量封装代码。在这种原则下,我觉得往领域Bean里放CRUD的数据库操作是我目前能想到的比较好的封装的方法,要不CRUD处理往哪里放?
8 楼 czx566 2009-01-05  
我想我和你一样思考过这个问题

如果愿意,你可以看看我博客的第3篇文章。


IOC有设计边界的~

7 楼 nfxu 2009-01-05  
czx566 写道
我这么理解的你问题

你目前在三层都用到了依赖注入,按照以往的惯例是:
    你的访问发起调用,action 对象由 容器生成,同时在action中应该
同时注入你action依赖的各个领域对象。

但你不想这么实现,你想action的对象依然由容器生成,但action和领域模型之间的关系由factory生成 或则new 生成?





我觉得这不是我能选择的,我没有别的选择。

目前action的对象是由Spring的application context生成的,这个application context是通过Web服务器里的web.xml在服务器启动时装载进入系统的。也就是说,struts2和Spring集成在了一起。

其他的层,例如service,也是通过application context注入到action里的。因为action由application context来管理,所以没有问题。

但现在领域Bean不好由application context来管理,因为不像service一样可以是单体,相反,要由service里的业务逻辑来灵活管理领域Bean的生命周期,也就是说,我觉得在业务逻辑里new各种领域Bean更为自然。

同时,我愿意在领域Bean里加入对数据库的访问以实现CRUD等操作,所以需要在领域Bean里注入DAO。

但现在领域Bean不归application context管理,如何注入由application context管理的DAO?DAO就像service、session factory一样,是单体,可以被application context管理。

6 楼 nighthawk 2009-01-05  
nfxu 写道
嗯。我说的往领域bean里注入session factory实际上是DAO,呵呵。

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

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

你要真是这么显式的引用,那你干脆new吧,spring也不需要了。没有意义
5 楼 czx566 2009-01-05  
的确,加了,测试要较复杂一些~

但更加oo

呵呵

凡事都有得有失~
4 楼 czx566 2009-01-05  
有持久化就不能做单体测试了么?


我不这么认为


3 楼 czx566 2009-01-05  
我这么理解的你问题

你目前在三层都用到了依赖注入,按照以往的惯例是:
    你的访问发起调用,action 对象由 容器生成,同时在action中应该
同时注入你action依赖的各个领域对象。

但你不想这么实现,你想action的对象依然由容器生成,但action和领域模型之间的关系由factory生成 或则new 生成?



2 楼 nfxu 2009-01-05  
嗯。我说的往领域bean里注入session factory实际上是DAO,呵呵。

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

也可以这么说,如何在通过Web容器启动了application context后,在代码里取得对这个application context的引用?就像这样:
  DomainBean myBean = applicationContext.getBean("domainBean");
1 楼 nighthawk 2009-01-05  
new了以后,你往领域bean里set一下DAO,或者直接new的时候构造,不就搞定了?
不过我对领域bean里注入session factory还是持否定的看法。
充血不是就说要用session factory去访问数据库

相关推荐

    充血模型设想实现(2010/07/30更新)

    综上所述,"充血模型设想实现"这一主题涵盖了软件设计的核心思想,即如何通过领域模型来表达和实现业务逻辑。在2010年的讨论中,可能深入探讨了如何利用充血模型提升代码质量、可维护性以及业务逻辑的一致性。结合...

    失血贫血充血胀血模型.docx

    1. 学习曲线:理解和实现充血模型可能需要对领域建模有较深的理解。 2. 测试复杂性:由于领域对象包含了复杂的业务逻辑,测试可能更为复杂。 【胀血模型】 胀血模型是对充血模型的一种扩展,领域对象不仅包含业务...

    基于六边形架构的充血领域模型设计源码——Freedom框架

    该项目为Freedom框架,是一款基于六边形架构的充血领域模型设计源码,采用Go语言开发,总计包含200个文件。文件类型涵盖了178个Go源文件、6个Markdown文档、4个TOML配置、4个YAML配置、2个SQL脚本、1个Git忽略规则、...

    基于GO的六边形架构框架,可支撑充血的领域模型范式代码实现.rar

    本资料主要关注的是使用Go语言实现的一个六边形架构框架,它特别适用于支持充血的领域模型范式。让我们深入探讨这些概念以及它们如何相互关联。 首先,我们来了解什么是六边形架构,也被称为端口和适配器架构。这种...

    对贫血和充血模型的理解

    Spring框架提供了灵活的依赖注入和面向切面编程(AOP)机制,允许开发者更容易地实现充血模型。这种方式更接近人的思维习惯,有助于代码的清晰和业务逻辑的集中管理。然而,充血模型也有它的挑战,比如可能会造成...

    领域模型说明及范例代码.zip

    在软件开发领域,模型设计是核心部分之一,它有助于我们理解和表述复杂的业务逻辑。领域模型(Domain Model)和贫血模型(Anemic Domain Model)是两种常见的模型设计模式,它们各有特点,适用于不同的场景。本资料...

    领域模型驱动设计1553265830.pdf

    领域模型分为贫血模型和充血模型两种。 - 贫血模型指的是领域对象只包含了数据访问方法(get和set方法)和一些简单的CRUD(创建、读取、更新、删除)方法,而所有的业务逻辑都放在了BusinessLogic层。 - 充血模型则...

    浅谈Asp.net中使用“充血模型”1

    在Asp.net开发中,"充血模型"是一种提倡领域对象拥有丰富行为和业务逻辑的设计模式,相对应于传统的"贫血模型"。"贫血模型"通常将数据模型、业务逻辑和数据访问分离,使得领域对象仅包含属性,而业务逻辑和数据操作...

    领域驱动(DDD)充血模式下,domain 与 Service以及Repository的解耦---DOMAIN EVENT

    领域模型是业务逻辑的抽象表示,它包含了业务领域的实体(Entities)、值对象(Value Objects)、领域服务(Domain Services)和仓储(Repositories)等元素。在充血模式下,这些组件拥有丰富的业务逻辑,而不仅仅是...

    领域驱动设计案例-盒马实践

    领域模型可以分为失血模型、贫血模型和充血模型三种类型。 失血模型 失血模型是基于数据库的领域设计方式,它指的是使用 POJO 数据对象来存储业务数据。在失血模型中,业务逻辑是分散的,分布在多个地方。 贫血...

    领域驱动设计学习总结(一)

    2. **限界上下文(Bounded Context)**:限界上下文是DDD中的一个重要概念,它定义了领域模型的边界,明确了模型在特定业务领域的适用范围和语义。 3. **领域统一语言(Ubiquitous Language)**:领域统一语言是...

    大白话领域驱动设计DDD视频教程

    第2章 领域分析模型 核心域,支撑子域,通用子域 微服务和DDD是什么关系? 传统模式下如何合理的划分各种域 基于DDD的方式进行域划分 什么是通用语言 什么是限界上下文? 限界上下文和子域的关系 基于电商系统按流程...

    DDD领域驱动设计day01.pdf

    领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法论,由Eric Evans在其同名著作中提出,旨在帮助开发者更好地理解和处理复杂的业务逻辑,通过深入挖掘领域知识来构建高质量的软件系统。DDD的核心是...

    论文研究 - 雅温得大学教学医院重症监护室充血性心力衰竭的模式和结果:跨领域研究

    背景:在我们所在的重症监护病房中,充血性心力衰竭(CHF)的数据很少。 这项研究旨在为雅温得大学教学医院的重症监护病房提供更好的CHF模式和预后知识。 方法:我们进行了为期21个月的描述性和回顾性研究。 我们从...

    领域驱动设计

    4. **限界上下文**:为了管理复杂度,DDD引入了限界上下文(Bounded Context)的概念,每个限界上下文定义了一组相关的领域模型和业务规则,它们之间通过接口和服务进行通信。 5. **事件溯源(Event Sourcing)**:这是...

    11丨实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?1

    2. 领域驱动设计:在需要紧密贴合业务领域模型的项目中,充血模型能够更好地体现业务实体及其行为。 3. 提升代码质量:追求更高质量的代码,减少不必要的转换和重复代码,提高整体系统的稳定性。 总的来说,选择...

    tbl-demo-service-master.zip

    那么领域模型的作用微乎其微,甚至可以忽略,数据转换的成本比领域模型带来的好处还多,这种情况其实就是在原有的分层架构中多加了一层,增加了项目的复杂性和工作量。 “领域驱动开发DDD”只有被正确地运用,才能...

    DDD领域驱动设计初探(6):领域服务 - 文章 - 伯乐在线1

    然而,遵循DDD的原则,我们应尽可能使领域模型丰满,保持“充血模型”,即将所有领域逻辑保留在领域层。因此,处理实体间关系的逻辑更适合放在领域服务中。 以权限管理为例,假设我们需要实现一个功能,将指定用户...

    自由:自由是一个基于六边形架构的框架,可以支撑充血的领域模型范式

    自由DDD框架自由是一个基于六边形架构的框架,可以支撑充血的领域模型范式。总览集成虹膜HTTP / H2C服务器和客户端集成普罗米修斯AOP工作者和无侵入上下文可扩展组件依赖注入&依赖倒置&开闭原则DDD和六边形架构...

Global site tag (gtag.js) - Google Analytics