简化Spring(2)--Model层

本文探讨了Spring框架下Model层的设计模式,提出了简化方案,即将DataObject作为纯数据载体,Manager类融合DAO与Service功能,并讨论了基于接口编程的适用场景。
  因为Spring自带的sample离我们的实际项目很远,所以官方一点的model层模式展现就靠Appfuse了。
    但Appfuse的model层总共有一个DAO接口、一个DAOImpl类、一个Service接口、一个ServiceImpl类、一个DataObject.....大概只有受惯了虐待的人才会欣然接受吧。
    另外,Domain-Driven逢初一、十五也会被拿出来讨论一遍。

    其实无论什么模式,都不过是一种人为的划分、抽象和封装。只要在团队里理解一致,自我感觉优雅就行了。
     我的建议是,一开始DO和Manager一生一旦包演全场,DO作为纯数据载体,而Manager类放置商业方法,用getHibernateTemplate()直接访问数据库,不强制基于接口编程。当某天系统复杂到你直觉上需要将DAO层和Service层分开时,再分开就好了。

    1.DataObject类
    
好听点也可以叫Domain Object。Domain Driven  Development虽然诱人,但因为Java下的ORM框架都是基于Data Mapper模式的,没有Ruby On Rails中那种Active Recorder的模式。所以,还是压下了这个欲望,Data Object纯粹作一个数据载体,而把数据库访问与商业逻辑操作统一放到Manager类中。

    2.Manager类
    我的Manager类是Appfuse中DAO类与Service类的结合体,因为:

     2.1 不想使用纯DAO
     以往的DAO是为了透明不同数据库间的差异,而现在Hibernate已经做的很好。所以目前纯DAO的更大作用是为了将来可以切换到别的ORM方案比如iBatis,但一个Pragmaic的程序员显然不会无聊到为了这个机会不大的理由,现在就去做一个纯DAO层,项目又不是Appfuse那样为了demo各种ORM方案而存在。

    2.2 也不使用纯的薄Service层
    在JPetStore里有一个很薄的Service层,Fascade了一堆DAO类,把这些DAO类的所有方法都僵硬的重复了一遍。而我认为Fascade的意义在二:
    一是Controller调用Manager甲的时候,总会伴随着调用Manager乙的某些方法。使用Fascade可以避免Controller零散的调用一堆Manager类。
    二是一个商业过程里可能需要同时调用DAO甲乙丙丁的方法。 

     这些时候,Fascade都是合理的。但我讨厌类膨胀,所以我宁愿在甲乙丙丁中挑一个来充当Fascade的角色。有耦合的问题吗?对一个不是死搬书的Designer来说,组件边界之内的类之间的耦合并不是耦合。

    3.去除不必要的基于接口编程
    众所周知,Spring是提倡基于接口编程的。
    但有些Manager类,比如SaleOrderManager ,只有5%的机会再有另一个Impl实现。95%时间里这两兄弟站一起,就像C++里的.h和.cpp,徒增维护的繁琐(经常要同步两个文件的函数声明),和代码浏览跳转时的不便(比如从Controler类跟踪到Service类时,只能跳转到接口类的相应函数,还要再按一次复杂的热键才跳转到实现类)
    连Martin Flower都说,强制每个类都分离接口和实现是过犹不及。只在有多个独立实现,或者需要消除对实现类的依赖时,才需要分离接口。

     3.1 DAO被强制用接口的原因
    Spring IOC本身是不会强制基于接口的,但DAO类一般要使用Spring的声明式事务机制,而声明式的事务机制是使用Spring AOP来实现的。Spring AOP的实现机制包括动态代理和Cgilib2,其中Spring AOP默认使用的Java动态代理是必须基于接口,所以就要求基于接口了。
    
    3.2 解决方法
    那就让Spring AOP改用CGLib2,生成目标类的子类吧,我们只要指定使用声明式事务的FactoryBean使用CGLib的方式来实现AOP,就可以不基于接口编程了。
    指定的方式为 设置proxyTargetClass为true。如下:
< bean  class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
id
="baseService"    abstract ="true" >
  
< property  name ="transactionManager"  ref ="transactionManager" />
  
< property  name ="proxyTargetClass"  value ="true" />

</ bean >

     又因为这些Service Bean都是单例,效率应该不受影响。

    4.总结
    对比Appfuse里面的5个类,我的Model层里只有VO作为纯数据载体,Manager类放商业方法。有人说这样太简单了,但一个应用,要划成几个JSP,一个Controller,一个Manager,一个VO,对我来说已经足够复杂,再要往上架墙叠屋,恕不奉陪,起码在我的项目范围里不需要。(但有很多项目是需要的,神佑世人)

    后记:迫于世人的压力, SpringSide还是把DAO和Service层分开了,但依然坚持不搞那么多接口。

相关文章
简化Spring(1)--配置文件
简化Spring(2)--Model层
简化Spring(3)--Controller层
简化Spring(4)--View层
### Spring AI Model 1.0.0 兼容的 Java 版本 Spring AI 是一个基于 Spring 生态系统构建的人工智能框架,旨在简化与大语言模型(LLM)和其他 AI 模型的集成。关于 `spring-ai-model-1.0.0` 的兼容性问题,官方文档和相关引用并未直接提及具体的 Java 版本要求。然而,根据 Spring Boot 和 Spring Framework 的通用依赖关系,可以推断出以下信息: Spring AI 构建在 Spring Boot 3.x 和 Spring Framework 6.x 的基础上[^1]。因此,`spring-ai-model-1.0.0` 的最低 Java 版本要求应为 **Java 17**,因为这是 Spring Boot 3.x 的最低支持版本[^2]。 以下是相关的配置和依赖示例,以确保环境一致性: ```xml <properties> <java.version>17</java.version> <spring-ai.version>1.0.0</spring-ai.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency> </dependencies> ``` 此外,如果需要使用特定的大模型服务(如阿里云百炼),还需要正确配置 API 密钥和 URL 地址[^4]。例如: ```yaml spring: ai: openai: base-url: https://dashscope.aliyuncs.com/compatible-mode/ api-key: 【替换为自己的API密钥】 chat: options: model: deepseek-r1 temperature: 0.7 ``` ### 注意事项 - 如果项目中使用了其他 Spring 组件或第三方库,请确保它们也兼容 Java 17。 - 需要测试项目的运行环境以验证是否存在潜在的不兼容问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值