使用Spring AOP实现活动记录模式

在班级设计中,我们应就每个班级的职责分配做出决定。 如果我们选择的不错,系统将更易于理解,维护和扩展。

几乎我们所有的项目都有一个持久层,即关系数据库,文档存储或仅XML文件。 通常,您将使用DAO模式在业务对象和数据存储之间实现抽象接口。

在这篇文章中,但我将解释另一种可以代替DAO模式使用的模式。 活动记录模式是一种体系结构模式,它迫使您对模型类实施CRUD操作,因此模型类本身负责保存,删除和从数据库加载。

要实现此模式,有许多策略可以遵循,但是对我而言,最好的方法是使用面向方面的编程 ,因为我们仍然保持关注点分离,有利于隔离的单元测试,而不破坏封装。

面向方面的编程需要将程序逻辑分解为不同的部分。 这些部分被称为横切关注点,因为它们“ 跨越 ”程序中的多个抽象。 横切关注点的示例可以是日志记录,事务管理器错误管理器拆分大型数据集 。 对于在这里没有太多秘密的方面的人们来说,要使用它们,您只需创建一个定义建议和切入点的方面,然后就可以执行您的方面了。

我想我们大多数人都使用了上一段中所述的面向方面的编程,但是使用ITD(类型间声明)功能的人会更少。

类型间声明提供了一种表达横切关注点的方法,这些关注点影响了模块的结构,从而使程序员可以声明另一个类的成员。

正如我们在我的国家说“ 不好说,但很好理解 “,ITD是从一个方面宣布新的组件属性,方法,注解 )的方式。

AspectJ是Java 的面向方面的扩展。 AspectJ支持ITD ,因此在本文中将使用它。 此外,我建议您安装AJDT插件,因为它将帮助您开发方面,并快速概述了哪些Java类已被方面化。

如果您不了解什么是ITD ,请不用担心,这是一个典型的概念示例,最好通过示例来理解。

让我们从一个简单的例子开始:

想象一下必须为汽车建模。 您将拥有一个带有某些属性的汽车类,在此示例中,三个属性( vin号,行驶里程model )就足够了。

public class Car {public void setVin(String vin) {this.vin = vin;}public String getVin() {return this.vin;}private String vin;public void setMileNum(int mileNum) { this.mileNum = mileNum;}public int getMileNum() {return this.mileNum;}private int mileNum;public void setModel(String model) {this.model = model;}public String getModel() {return this.model;}private String model; }

这是一个具有三个属性以及它们的gettersetterPOJO

现在我们要添加持久层,但是在这种情况下,我们将POJO持久化为 XML文件而不是数据库。 因此,应将Car对象转换为XML流。 为此,将使用JAXB批注。 对于那些不知道的人, JAXB允许开发人员将Java类映射到XML表示,反之亦然。

我确信,想到的第一个想法是使用@XmlRootElement注释Car类(在JAXB中映射根元素的注释)。 不要那样做,使用方面 。 您的第一个任务是尝试维护Car文件尽可能简单。 要使用ITD添加注释,很简单:

public aspect Car_Jaxb {declare @type: Car: @XmlRootElement;
}

使用@type可以公开注释哪个成员。 在这种情况下,只能上课。 其他方法是@method@constructor@field 。 然后元素模式应该被注释,在这种情况下是Car类,但是您可以使用任何正则表达式,例如o rg.alexsotob .. *。 最后是注释

下一步是使用JAXB类来编组/解组对象。 在此示例中,我使用spring-oxm软件包,简要地您将了解原因。 Spring-oxmspring-core的一部分,其中包含用于处理O / X Mapping的类

这个spring模块为每个受支持的Xml绑定包含一个类。 在我们的情况下, Jaxb2Marshaller用作编组器和解组器。

您可能正在考虑创建一个服务类,在其中注入Jaxb2Marshaller实例。 该服务将包括两个方法(保存和加载),以Car类作为参数或返回值。 抱歉,这样做是要实现DAO模式。 让我们实现Active Record模式方法。 正如您可能会想到的, aspectj可以帮助您避免将概念混入同一源文件中。

让我们更新以前的方面文件,以便JAXB所需的所有逻辑都在同一文件中。

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;public aspect Car_Jaxb {declare @type: Car: @XmlRootElement;@Autowiredtransient Jaxb2Marshaller Car.marshaller;public void Car.save(OutputStream outputStream) throws IOException {this.marshaller.marshal(this, new StreamResult(outputStream));}public Car Car.load(InputStream inputStream) throws IOException {return (Car)this.marshaller.unmarshal(new StreamSource(inputStream));}}

看到除了注释Car类,我们还创建了两个方法和一个带注释的属性。 属性必须遵循与方法,< 类名 >点(。)和< 属性名 >相同的规则。 请注意,在这种情况下,属性是瞬态的,因为不应绑定到XML文件中。

最后一步是在spring上下文文件中配置marshaller

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:oxm="http://www.springframework.org/schema/oxm"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><oxm:jaxb2-marshaller id="marshaller"><oxm:class-to-be-bound name="org.alexsotob.itd.Car"/></oxm:jaxb2-marshaller></beans>

没有太多秘密。 现在让我们编写一个单元测试代码。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="/context.xml")
public class CarOxmBehaviour {@Testpublic void shouldSaveCarToXml() throws Exception {//GivenCar car = new Car();car.setMileNum(1000);car.setModel("Ferrari");car.setVin("1M8GDM9AXKP042788"); //From http://en.wikipedia.org/wiki/Vehicle_Identification_Number//WhenByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();car.save(byteArrayOutputStream);//ThenString expectedMessage = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><car><mileNum>1000</mileNum><model>Ferrari</model><vin>1M8GDM9AXKP042788</vin></car>";String xmlMessage = byteArrayOutputStream.toString("UTF-8");assertThat(the(xmlMessage), isEquivalentTo(the(expectedMessage)));  }}

用令人惊讶的NullPointerException运行红色的junit类和BOOMMarshaller是在Spring上下文中创建的,但是没有注入到Car类中(Car不是由spring 容器管理的,因此无法注入)。 现在,我想您是在告诉自己:“ 我告诉您,服务层会更好,因为它将由Spring进行管理,并且自动装配功能会完美工作 。” 但是,拭目以待。 如何使用spring-aspects模块? Spring Aspects包含一个注释驱动的方面( @Configurable ),允许任何对象的依赖项注入,无论是否受容器控制。 因此,让我们应用最后两个更改,应用程序将运行。

首先是创建一个新的aspectj文件,以将Car类注释为Configurable

import org.springframework.beans.factory.annotation.Configurable;public aspect Car_Configurable {declare @type: Car: @Configurable;}

最后修改spring上下文文件以允许@Configurable注释。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:oxm="http://www.springframework.org/schema/oxm"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><oxm:jaxb2-marshaller id="marshaller"><oxm:class-to-be-bound name="org.alexsotob.itd.Car"/></oxm:jaxb2-marshaller><context:spring-configured></context:spring-configured>
</beans>

添加< context:spring-configured > </ context:spring-configured >命名空间就足够了。 结果,任何时候您实例化一个对象(通过“ new ”关键字)时,Spring都会尝试对该对象执行依赖注入。

现在再次运行单元测试,绿色将侵入您的计算机:D。

ITD是一个很好的解决方案,可以自己负责设计类。 它为您提供了编写可维护且易于理解的代码的机会,而不会丢失封装。 当然,您应该注意不要在各方面的类中具有较高的耦合,而应将它们转换为“上帝类”。

注意,实现相同的方法但是使用关系数据库,就像将Jaxb2Marshaller更改为EntityManager一样简单。

我希望您发现这篇文章有用。

下载完整代码

参考:来自JCG合作伙伴的 Spring AOP实现活动记录模式   在一个罐子统治他们所有博客的亚历克斯·索托。


翻译自: https://www.javacodegeeks.com/2012/02/implementing-active-record-pattern-with.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/373723.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php socketconnect连接失败_PHP设计模式之模板方法模式

模板方法模式&#xff0c;也是我们经常会在不经意间有会用到的模式之一。这个模式是对继承的最好诠释。当子类中有重复的动作时&#xff0c;将他们提取出来&#xff0c;放在父类中进行统一的处理&#xff0c;这就是模板方法模式的最简单通俗的解释。就像我们平时做项目&#xf…

数据库建表练习(10.11作业)

转载于:https://www.cnblogs.com/HRZJ/p/5951897.html

从程序员到CTO的Java技术路线图

时间:2013-05-29 17:39来源:www.chengxuyuans.com在技术方面无论我们怎么学习&#xff0c;总感觉需要提升自已不知道自己处于什么水平了。但如果有清晰的指示图供参考还是非常不错的&#xff0c;这样我们清楚的知道我们大概处于那个阶段和水平。 Java程序员 高级特性 反射、泛型…

设置Spring 3开发环境

本教程简要说明了如何设置典型的环境来开发基于Spring的应用程序。 除了可以正常工作的Windows XP客户端具有足够的CPU能力和内存外&#xff0c;本教程没有其他先决条件。 在教程中&#xff0c;我们将需要安装以下组件&#xff1a; Java 6 JDK更新26 用于Java EE开发人员的Ecl…

js中window.onload 与 jquery中$(document.ready()) 测试

js中window.onload 与 jquery中$(document.ready())区别&#xff0c;验证代码如下(调换js代码和Jquer代码书写顺序测试&#xff0c;运行结果一样&#xff0c;因此与代码书写位置没关系)&#xff1a;<html> <head> <script typetext/javascript srcjquery-1.11.1…

Java中的定制国际化(i18n)

国际化&#xff08;i18n&#xff09;在我们的软件项目中非常重要。 它主要带来以下好处&#xff1a; 将UI字符串外部化为除代码文件之外的外部文件&#xff0c;以及易于管理的UI内容。 支持多种语言。 在这篇文章中&#xff0c;将为Eclipse和Java项目提供一个简短的i18n实际示…

SEO 百度后台主动推送链接

实践步骤&#xff0c;先用爬虫程序将本网站的所有连接爬取出来&#xff0c;再用python文件处理程序把爬虫来的东东整理成一行一个链接的文本格式。再用postman接口测试工具&#xff0c;使用post方式&#xff0c;将所有的链接post过去&#xff0c;这样主动推送是最为快速的提交方…

nyoj--127--星际之门(一)(生成树的数量)

星际之门&#xff08;一&#xff09; 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;3描述公元3000年&#xff0c;子虚帝国统领着N个星系&#xff0c;原先它们是靠近光束飞船来进行旅行的&#xff0c;近来&#xff0c;X博士发明了星际之门&…

Oracle 常用的一些函数

字符函数 SELECT UPPER(hello WORLD) FROM DUAL; //将小写字母变为大写字母SELECT LOWER(hello WORLD) FROM DUAL; //将大写字母变为小心字母SELECT INITCAP(hello WORLD) FROM DUAL; //将字符串的首字母大写SELECT CONCAT(hello, world) FROM DUAL; //字符串拼…

JavaScript 学习随记——==和===及常见元素的真假值

“” 和 “” 符合的使用 <script>/*** 表示可以经过自动转换&#xff0c;比较的是数值*///example01if(1 true && false 0 && true 1){console.log(1true);console.log(" 比较的是等号两边数据的值是否相等&#xff08;可以经过自动转换&#…

JavaScript学习随记——数组一

数组的创建及length属性 <script type"text/javascript" charset"utf-8">// 数组创建方式一,此种方式写的时候比较麻烦var arrnew Array();// 数组创建方式二var arr [1,2,3,4,true,str,new Date()];console.log("arr.length&#xff1a;"…

Spring和石英:多作业计划服务

作业调度对于应用程序来说是如此重要。 尤其是在大型项目中&#xff0c;处理大量工作可能是一个问题。 Spring和Quartz为解决该问题带来了巨大的好处。 本文介绍了如何通过使用Spring和Quartz轻松地计划多个作业。 二手技术&#xff1a; JDK 1.6.0_21 春天3.1.1 石英1.8.5 M…

反射的简单应用

首先有一个类 1 using System;2 using System.Collections.Generic;3 using System.Linq;4 using System.Text;5 using System.Threading.Tasks;6 7 namespace ConsoleApplication18 {9 public class demo 10 { 11 public string name "程序员"; 12…

JavaFX 2.0示例介绍书

我最近完成了有关JavaFX 2.0 SDK新版本的书的编写&#xff0c;并且已经将它放在您附近的书店&#xff08; Amazon &#xff09;的书架上。 该书将逐步指导您完成JavaFX 2.0的来龙去脉。 当您遇到一章时&#xff0c;将看到一些菜谱&#xff0c;这些菜谱将带来一个问题&#xff0…

双纵坐标的绘图命令_工程师绘图必备软件——OriginLab 2019b

点击右上角关注&#xff0c;尽享后续精品软件OriginLab 2019b是OriginLab OriginPro 2019版本的加强版&#xff0c;这个软件对于许多人来讲并不陌生&#xff0c;可以说是科学家和工程师的绘图必备软件。新的版本也带来许多改变&#xff0c;软件拥有多种功能&#xff0c;这个版本…

Spring远程支持和开发RMI服务

Spring远程支持简化了启用远程服务的开发。 当前&#xff0c;Spring支持以下远程技术&#xff1a;远程方法调用&#xff08;RMI&#xff09;&#xff0c;HTTP调用程序&#xff0c;Hessian&#xff0c;Burlap&#xff0c;JAX-RPC&#xff0c;JAX-WS和JMS。 远程方法调用&#xf…

ToString:身份哈希码的十六进制表示形式

我以前在方便的Apache Commons ToStringBuilder上写过博客&#xff0c;最近有人问我&#xff0c;在生成的String输出中出现的看似神秘的文本是什么构成的。 询问该问题的同事正确地推测出他正在查看的是哈希码&#xff0c;但与他实例的哈希码不匹配。 我解释说ToStringBuilder将…

登录id 黑苹果_黑苹果MacOSCatalina无法登录AppStore修复

先上图&#xff1a;惨红色的提示信息&#xff0c;把你拒之App Store门外&#xff0c;但是对之放弃、不与之斗争不是我们的节奏&#xff0c;请看破敌攻略&#xff1a;1.查看你的“关于本机”-->“概览”-->“系统报告”&#xff0c;如图&#xff1a;找到你的“网络”-->…

Web开发的入门指导

Web开发的入门指导web开发编程技术你点开此文&#xff0c;说明你对Web开发是有兴趣的&#xff0c;或者你正在思考开始学习Web开发。在这里&#xff0c;我会告诉你成为一名Web开发者的路线&#xff0c;是对初学者关于Web开发的指导。这篇文章不会教你如何写代码&#xff0c;而是…

过滤日志中不相关的堆栈跟踪行

我喜欢堆栈痕迹。 不是因为我喜欢错误&#xff0c;而是因为发生错误的那一刻&#xff0c;堆栈跟踪是无价的信息源。 例如&#xff0c;在Web应用程序中&#xff0c;堆栈跟踪向您显示完整的请求处理路径&#xff0c;从HTTP套接字到过滤器&#xff0c;Servlet&#xff0c;控制器&a…