织梦系统做导航网站,ip动态地址做网站,做外贸网站用什么软件,茂名市住房和城乡建设局在JavaCodeGeeks主持的上一篇文章中#xff0c;我们的JCG合作伙伴 Tomasz Nurkiewicz介绍了使用State设计模式进行领域驱动设计的介绍 。 在该教程的最后#xff0c;他承认他省略了如何将依赖项#xff08;DAO#xff0c;业务服务等#xff09;注入域对象的过程。 但是我们的JCG合作伙伴 Tomasz Nurkiewicz介绍了使用State设计模式进行领域驱动设计的介绍 。 在该教程的最后他承认他省略了如何将依赖项DAO业务服务等注入域对象的过程。 但是他答应在随后的帖子中解释细节。 好了现在该看看如何完成此工作了。 托马斯Tomasz继续提供非常具有启发性的教程 。 让我们看看他怎么说 注意对原始帖子进行了少量编辑以提高可读性 在开始讨论我们的主要主题之前我希望您先想一想关于您可以想象的最佳Java EE应用程序设计。 不管使用Spring还是EJB3都没有关系因为它们非常相似可能您会建议一种类似于以下的方法。 从后端开始您有 域对象 它们是直接映射到数据库关系的简单POJO。 POJO很棒因为许多框架都很好地理解了JavaBean样式的属性。 数据访问层 –通常为无状态服务它们包装数据库访问代码JDBCHibernateJPAiBatis或您想要的任何东西以隐藏其复杂性并提供一定程度的泄漏抽象。 DAO之所以出色是因为它们隐藏了令人讨厌且笨拙的JDBC逻辑这就是为什么有人质疑使用JPA时对DAO的需求它充当数据库和对象之间的或多或少的翻译器。 业务服务层 –在域对象上运行的另一组无状态服务。 典型的设计引入了一个对象图这些对象采用或返回域对象并对其执行一些逻辑同样通常通过数据访问层访问数据库。 服务层很棒因为它专注于业务逻辑将技术细节委托给DAO层。 用户界面 –如今通常是通过网络浏览器。 用户界面之所以如此出色是因为……事实如此。 美丽不是吗 现在睁开眼睛是时候洗个冷水了。 服务和DAO都是无状态的因为Spring和EJB3偏爱此类因此我们学会了使用它。 另一方面POJO是“无逻辑的” –它们仅包含数据不对其进行操作就保持其状态并且不引入逻辑。 如果考虑将“ reservation”域对象引入我们的应用程序我们会立即想到映射到RESERVATIONS数据库表ReservationDaoReservationServiceReservationController等的Reservation POJO。 还是看不到问题吗 您如何形容“对象” 它是一些具有内部封装状态的虚拟实体以及一些具有对该状态的显式访问权限的公共操作。 基于对象的编程的最基本概念是将数据和对该数据进行操作的过程放在一起并紧密关闭它们。 现在看看您有史以来最好的设计您真的需要物体吗 这是SpringEJB3Hibernate和其他完善框架的秘密。 我们所有人下意识地试图忘记的秘密我们不再是OOP程序员 POJO不是对象它们只是数据结构数据集合。 Getter和Setter不是真正的方法实际上您最后一次手工编写它们是什么时候 实际上自动生成它们以及在属性更改时重构添加和删除的需求有时会令人沮丧。 缺省情况下仅使用具有公共字段的结构会不会更简单 另一方面请查看所有这些出色的无状态服务。 他们没有任何状态。 尽管它们在域对象上运行但它们不是域对象的一部分甚至不聚集它们低内聚性。 所有数据都通过方法参数显式传递。 它们也不是对象它们只是在公共名称空间对应于类名称上任意聚集的过程的集合。 在合同中OOP中的方法也是幕后的过程但是具有对该引用的隐式访问该引用指向对象实例。 每当我们调用ReservationService或ReservationDao明确提供Reservation POJO引用作为参数之一时我们实际上是在重新发明OOP并手动对其进行编码。 面对现实我们不是OOP程序员因为我们需要的一切都是五十年前发明的结构和过程。 每天有多少Java程序员在使用继承和多态 上一次编写具有私有状态而没有getter / setter且只有很少方法可以访问的对象的时间是什么时候 上次使用非默认构造函数创建对象的时间是什么时候 幸运的是Spring采取了什么措施它带回了更大的力量。 该功能称为AspectJ 。 在上一篇文章中我创建了一个保留实体该实体具有三种业务方法acceptcharge和cancel。 将与域对象有关的业务方法直接放置在该对象中看起来真的很好。 无需调用ReservationService.acceptreservation我们只需运行Reservation.accept即可它更加直观且噪音小。 更好的是编写 Reservation res new Reservation()
//...
res.persist() 而不是调用DAO或直接使用EntityManager 我对域驱动设计了解不多但是我发现这种基本的重构是进入DDD世界以及返回到OOP必须走的第一步。 Reservations的accept方法最终将需要将一些逻辑委托给外部服务例如记帐或发送电子邮件。 自然此逻辑不是保留域对象的一部分应该在其他地方实现高内聚性。 问题是如何将其他服务注入域对象。 当所有服务都由Spring管理时一切都很简单。 但是当Hibernate自己创建域对象或使用new运算符创建对象时Spring对此实例一无所知无法处理依赖项注入。 那么保留POJO如何获得封装必要逻辑的Spring bean或EntityManager 首先将Configurable批注添加到您的域对象中 Configurable
Entity
public class Reservation implements Serializable {//...
} 这告诉Spring保留POJO应该由Spring管理。 但是如上所述Spring不了解正在创建的Reservation实例因此没有机会自动装配和注入依赖项。 这是AspectJ的用处。您需要做的就是添加 context:load-time-weaver/ 到您的Spring XML描述符。 这个非常短的XML代码片段告诉Spring它应该使用AspectJ加载时编织LTW。 现在当您运行应用程序时 java.lang.IllegalStateExceptionClassLoader [org.apache.catalina.loader.WebappClassLoader]不提供addTransformerClassFileTransformer方法。 指定一个定制的LoadTimeWeaver或使用Spring的代理启动Java虚拟机-javaagentspring-agent.jar 在org.springframework.context.weaving.DefaultContextLoadTimeWeaver中。 setBeanClassLoaderDefaultContextLoadTimeWeaver.java:82 在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中。 initializeBeanAbstractAutowireCapableBeanFactory.java:1322 在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中。 doCreateBeanAbstractAutowireCapableBeanFactory.java:473 …另外59个 它将失败……Java不是魔术因此在继续之前请先解释一下。 在上面添加XML代码段并不能解决任何问题。 它只是告诉Spring我们正在使用AspectJ LTW。 但是当应用程序启动时它不会找到AspectJ代理并且会适当地告诉我们有关它的信息。 如果按照建议将-javaagentspring-agent.jar添加到我们的JVM命令行参数会发生什么 这个Java代理仅仅是JVM的插件它覆盖了每个类的加载。 首次加载Reservation类时代理会发现Configurable批注并将某些特殊的AspectJ方面应用于该类。 更精确地说正在修改Reservation类的字节码从而覆盖所有构造函数和反序列化例程。 多亏了这种修改每当实例化新的Reservation类时除了正常的初始化之外Spring提供的方面添加的那些附加例程都将执行依赖项注入。 因此从现在开始增强的Reservation类是Spring感知的。 保留是由HibernateStruts2创建还是使用new运算符都没有关系。 隐藏的方面代码始终负责调用Spring ApplicationContext并要求其将所有依赖项注入域对象。 让我们将其用于试驾 Configurable
Entity
public class Reservation implements Serializable {PersistenceContextprivate transient EntityManager em;Transactionalpublic void persist() {em.persist(this);}
//...
} 这不是一个错误–我将JPA规范中的EntityManger直接注入域对象。 我还将Transactional批注放置在persist方法上。 在普通的Spring中这是不可能的但是由于我们使用了Configurable批注和AspectJ LTW因此下面的代码是完全有效的并且可以按预期工作对数据库发出SQL并提交事务 Reservation res new Reservation()
//...
res.persist() 当然您也可以将常规依赖项其他Spring Bean注入到域对象中。 您可以选择使用自动装配 Autowire或更好的Resource批注或手动设置属性。 后一种方法为您提供了更多控制权但是迫使您在域对象中为Spring bean添加setter并定义与域对象相对应的另一个bean bean class com.blogspot.nurkiewicz.reservations.Reservation !-- ... --
/bean 请注意我没有提供此bean的名称/ ID。 如果可以的话应该将相同的名称传递给Configurable批注。 一切都像魅力一样运作但是我们如何在现实生活中使用这一惊人功能 首先我们必须设置您的单元测试以使用Java代理。 在IntelliJ IDEA中我只是添加了 -javaagentD/my/maven/repository/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar JUnit运行配置中的“ VM参数”文本字段。 如果将其添加到默认值“编辑默认值”按钮则此参数将应用于您运行的每个新单元测试。 但是配置IDE并不像配置构建工具希望是Maven那么重要。 首先您必须确保Spring Java代理已下载且可用。 感谢Maven的依赖关系解析可以通过添加以下依赖关系轻松实现 dependencygroupIdorg.springframework/groupIdartifactIdspring-agent/artifactIdversion2.5.6/versionscopetest/scope
/dependency 测试代码实际上并不需要JAR但是通过添加此依赖项我们保证在测试运行之前已下载JAR。 然后对surefire插件配置进行简单的调整 plugingroupIdorg.apache.maven.plugins/groupIdartifactIdmaven-surefire-plugin/artifactIdconfigurationforkModealways/forkModeargLine-javaagent:${settings.localRepository}/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar/argLine/configuration
/plugin 真的很简单–可以使用maven存储库路径安全地构造spring-agent.jar的位置。 此外还必须设置forkMode以便在执行每个测试之前重新加载类并导致LTW发生。 我认为配置您的应用服务器和/或启动脚本不需要任何进一步的说明。 这就是通过加载时编织进行Spring和AspectJ集成的全部内容。 很少有简单的配置步骤和域驱动设计的全新世界出现。 我们的领域模型不再脆弱实体变得“智能”业务代码更加直观。 最后但并非最不重要的一点–您的代码将是面向对象的而不是过程性的。 当然您可能不喜欢加载时编织因为它会干扰JVM类的加载。 还有另一种方法称为编译时编织它在编译时而不是在类加载时编织方面。 两种方法都有其优缺点以后我将尝试将它们进行比较。 确实这是非常有趣的方法。 就是这样我们的JCG合作伙伴 Tomasz Nurkiewicz提供了一个紧凑指南指导如何使用Spring和AspectJ的加载时间编织方式将依赖项注入域对象 。 如果您喜欢这个别忘了分享。 编码愉快 相关文章 在域驱动设计中使用状态模式 使用Spring AspectJ和Maven进行面向方面的编程 依赖注入–手动方式 JBoss 4.2.x Spring 3 JPA Hibernate教程 翻译自: https://www.javacodegeeks.com/2011/02/domain-driven-design-spring-aspectj.html