精华帖 (0) :: 良好帖 (0) :: 新手帖 (7) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-01-07
aop注入很好很强大
|
|
返回顶楼 | |
发表时间:2009-01-07
wangyugod 写道 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来完成。 我知道你说的这种情况。但你说的那些对我来说是在太高级了,我目前没有能力处理好。另外,从理论上说,我是不太愿意用太多的框架的,这产生太多的依赖。像这些AOP,Spring interceptor,听着很牛逼,可使得本来比较简单的结构变得复杂,产生过多的依赖,我是没有信心的。 1 struts,我用的就是actions,他的tag lib 我尽量不用,而是用标准的JSTL。其他我用Tiles和Validator。 2 spring,我就用IOC,其他的,白送都不要。 3 hibernate,我只用标准的sessionFactory.getCurrentSession(),和其中的transaction,使用代码声明事务。不用AOP等什么的。 为的什么,就是可维护性。关于在领域Bean里写CRUD,对我是最好的选择。我可以保证一个清晰,易于理解和维护扩展的系统。 |
|
返回顶楼 | |
发表时间:2009-01-07
samm 写道 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提供的工具类。 好,谢谢,我明白了。 我的数据库事务控制采用的是hibernate本身提供的,也就是这个样子: Session session = sessionFactory.getCurrentSession(); try { session.beginTransaction(); businessList = session.createQuery("from Business").list(); session.getTransaction().commit(); } catch (Exception e) { session.getTransaction().rollback(); throw e; } service层从整体上来说只是对上(Web/容器)提供服务,不应该依赖于Web,所以我的service里没有任何Web相关的API调用,只有标准的JSE类或其他的POJO类。所以我倾向于不从Web context里获取application context。 |
|
返回顶楼 | |
发表时间:2009-01-07
DanielYWoo 写道 实施证明,充血模型是Martin大叔的失败的理论之一
JPA/EJB3要是用充血模型,甚至涨血模型,那就死定了 lz不要在域模型这上面费心思,域模型还是POJO最好用 再说了,其实持久化等功能本来从OO角度来看也不是域模型的职责 你这个架构实在是太别扭了 另外,IoC是有边界的,哪些bean需要从IoC获得,哪些需要new,哪些需要用factory/builder等pattern创建,这个要看具体架构需求。就域模型来说,new一下就可以了,除非你要spring cglib做aop 老实说,我个人用充血模型觉得挺好的。 领域Bean里有CRUD操作应该有一部分人这么用吧?如果是的,我就知足了。可能这个是不太好,但目前我还不想改变,可以理解为我没有能里做的更好。呵呵。 |
|
返回顶楼 | |
发表时间:2009-01-08
我觉得你可以去看看《领域驱动设计》这本书,它定义的领域模型要素里面,其实将一个Domain Object分成了Domain 和 Repository,Domain 处理业务逻辑,不和持久层相关,Repository处理CRUD等持久层相关的操作。而Service是处理需要多个Domain协同操作的业务。整个模型中,只有Repository和底层的持久层相关。由于Java语言本身的特性,不能想Rails中那样将Domain和Repository合并成一个对象。
|
|
返回顶楼 | |
发表时间:2009-01-08
charles_zuo 写道 我觉得你可以去看看《领域驱动设计》这本书,它定义的领域模型要素里面,其实将一个Domain Object分成了Domain 和 Repository,Domain 处理业务逻辑,不和持久层相关,Repository处理CRUD等持久层相关的操作。而Service是处理需要多个Domain协同操作的业务。整个模型中,只有Repository和底层的持久层相关。由于Java语言本身的特性,不能想Rails中那样将Domain和Repository合并成一个对象。
嘿嘿,我明白我是个半吊子, 你说的书我没读过,书太厚,很少读,不过我会在网上找找短一些的资料看看的,谢谢啦。 |
|
返回顶楼 | |
发表时间:2009-01-09
折腾啊。。。还要承担连接管理啊什么的成本。
|
|
返回顶楼 | |
发表时间:2009-01-09
连接管理?没有啊,顶多是事务边界需要手工指定啊:
Session session = sessionFactory.getCurrentSession(); try { session.beginTransaction(); businessList = session.createQuery("from Business").list(); session.getTransaction().commit(); } catch (Exception e) { session.getTransaction().rollback(); throw e; } |
|
返回顶楼 | |
发表时间:2009-01-09
如果你考虑用工厂的对象来new 领域模型的话
事务依然是可 配置的~ |
|
返回顶楼 | |
发表时间:2009-01-13
其实仔细理解 领域模型的概念就知道了。 service服务层是协调domain对象之间的关系的。相当于一个facade.
遇到你这种情况,可以采用这种方式 service1-->invoke domain 假设domain中要使用到service2. 那么应该通过domain的方法传入,即将service2注入service1,然后通过参数传递到domain中 service1{ method(){ domain.method1(service2Instatnce ,parameters); } 如果domain要使用自身service的引用。那么就直接 domain.method2(this,parameters); 域对象只接收参数的service,而客户端不直接调用domain增加隔离性即可。 |
|
返回顶楼 | |