面向切面编程应用_应用面向方面的编程

面向切面编程应用

1.引言

面向方面编程的主要目标是将跨领域关注点分离。 当我们谈论跨领域的关注时,我们指的是在我们的系统或应用程序中的多个地方使用的通用功能。 这些概念包括:

  • 记录中
  • 交易管理
  • 错误处理
  • 监控方式
  • 安全

实现这种分离的方法是将这些概念模块化。 这将使我们保持业务逻辑类整洁,仅包含设计该类的代码。 如果我们不对这些问题进行模块化,则会导致代码纠结(该类包含不同的问题)和代码分散(相同的问题将散布在整个系统中)。

在此示例中,我们有一个Spring MVC应用程序,该应用程序访问所请求的数据(客户和订单)并显示一个包含其信息的页面。 我们可以看一下不同的层:

aop1

在上图中,我们可以理解,功能分散在不同的类中(在每个服务中实现监视),并且某些类包含不同的关注点(例如,ClientController类包含日志记录和异常处理)。 为了解决这个问题,我们将编写一些方面来实现我们的跨领域关注点。 目标是实现以下模型:

aop2

每个类仅包含与业务逻辑相关的代码,而各方面将负责拦截代码以注入跨领域的关注点。

让我们看一个例子。

  • 源代码可以在github上找到。

2.检查控制器代码

ClientController:

@Controller
public class ClientController {@Autowiredprivate ClientService clientService;private static Logger mainLogger = LoggerFactory.getLogger("generic");private static Logger errorLogger = LoggerFactory.getLogger("errors");@RequestMapping("/getClients")public String getClients(Model model, @RequestParam("id") int id) {mainLogger.debug("Executing getClients request");try {Client client = clientService.getClient(id);model.addAttribute("client", client);} catch (DataAccessException e) {errorLogger.error("error in ClientController", e);NotificationUtils.sendNotification(e);return "errorPage";}return "showClient";}
}

该控制器的目的在于检索一个客户端并返回一个显示其信息的视图,但是,如您所见,该代码包含其他逻辑。 一方面,它处理服务可能引发的异常,并将其重定向到错误页面。 另一方面,如果发生错误,它会生成日志记录信息和通知发送。 所有这些代码对于该应用程序中的所有控制器(可能还有其他类)都是通用的。

的确,我们本可以使用@ControllerAdvice批注来集中处理异常,但是本文的目标是了解如何使用Spring AOP完成它。

订单控制器也会发生同样的情况。 我不会在这里包括它,因为我不想让帖子变得多余。 如果您想检查一下,可以获取上一个链接中包含的源代码。

3.检查服务代码

客户服务:

@Service("clientService")
public class ClientServiceImpl implements ClientService {@Autowiredprivate ClientRepository clientRepository;private static Logger mainLogger = LoggerFactory.getLogger("generic");private static Logger monitorLogger = LoggerFactory.getLogger("monitoring");@Override@Transactional(readOnly = true)public Client getClient(int id) {mainLogger.debug("Accessing client service");long startTime = System.currentTimeMillis();Client client = clientRepository.getClient(id);long totalTime = System.currentTimeMillis() - startTime;monitorLogger.info("Invocation time {}ms ", totalTime);return client;}
}

除了服务调用外,它还包含日志记录的生成和每个调用中执行时间的监视。

如果需要使用程序化事务管理,我们还可以使用方面来模块化事务管理,但是在本示例中并非如此。

4.数据访问层

ClientRepositoryImpl:

@Repository
public class ClientRepositoryImpl implements ClientRepository {private JdbcTemplate template;private RowMapper<Client> rowMapper = new ClientRowMapper();private static final String SEARCH = "select * from clients where clientId = ?";private static final String COLUMN_ID = "clientId";private static final String COLUMN_NAME = "name";public ClientRepositoryImpl() {}public ClientRepositoryImpl(DataSource dataSource) {this.template = new JdbcTemplate(dataSource);}public Client getClient(int id) {return template.queryForObject(SEARCH, rowMapper, id);}private class ClientRowMapper implements RowMapper<Client> {public Client mapRow(ResultSet rs, int i) throws SQLException {Client client = new Client();client.setClientId(rs.getInt(COLUMN_ID));client.setName(rs.getString(COLUMN_NAME));return client;}}
}

该代码不包含任何横切关注点,但我将其包括在内以显示所有示例应用程序层。

5,激活AOP

要配置AOP,必须导入以下依赖项:

<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>3.2.1.RELEASE</version>
</dependency>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.6.8</version>
</dependency>

在Spring配置文件中,我们需要添加以下标签:

<context:component-scan base-package="xpadro.spring.mvc.aop"/>
<aop:aspectj-autoproxy/>

component-scan标签将在基本包中搜索,以查找我们的方面。 要使用自动扫描,您不仅需要使用@Aspect注释定义方面类,而且还需要包含@Component注释。 如果不包括@Component,则需要在xml配置文件中定义方面。

6,集中错误处理

我们将使用@Around建议来编写方面。 该建议将截获所有使用@RequestMapping注释进行注释的方法,并将负责调用该方法,并捕获服务引发的异常。

@Component
@Aspect
public class CentralExceptionHandler {private static Logger errorLogger = LoggerFactory.getLogger("errors");@Around("@annotation(org.springframework.web.bind.annotation.RequestMapping) && target(controller)")public String handleException(ProceedingJoinPoint jp, Object controller) throws Throwable {String view = null;try {view = (String) jp.proceed();} catch (DataAccessException e) {errorLogger.error("error in {}", controller.getClass().getSimpleName(), e);NotificationUtils.sendNotification(e);return "errorPage";}return view;}
}

@Target批注允许我们引用被拦截的类。 现在我们有了方面处理的异常处理,因此我们可以在控制器中摆脱这种逻辑。

@Controller
public class ClientController {@Autowiredprivate ClientService clientService;private static Logger mainLogger = LoggerFactory.getLogger("generic");//private static Logger errorLogger = LoggerFactory.getLogger("errors");@RequestMapping("/getClients")public String getClients(Model model, @RequestParam("id") int id) {mainLogger.debug("Executing getClients request");//try {Client client = clientService.getClient(id);model.addAttribute("client", client);//} catch (DataAccessException e) {//errorLogger.error("error in ClientController", e);//NotificationUtils.sendNotification(e);//return "errorPage";//}return "showClient";}	
}

仅需注意,您可能会通过以下建议截获控制器抛出的异常:

@AfterThrowing(pointcut="@annotation(org.springframework.web.bind.annotation.RequestMapping)", throwing="e")

但是请注意,此建议不会阻止异常的传播。

7,集中日志

日志记录方面有两个建议,一个关于控制器日志,另一个关于服务日志:

@Aspect
@Component
public class CentralLoggingHandler {private static Logger mainLogger = LoggerFactory.getLogger("generic");@Before("@annotation(org.springframework.web.bind.annotation.RequestMapping) && @annotation(mapping)")public void logControllerAccess(RequestMapping mapping) {mainLogger.debug("Executing {} request", mapping.value()[0]);}@Before("execution(* xpadro.spring.mvc.*..*Service+.*(..)) && target(service)")public void logServiceAccess(Object service) {mainLogger.debug("Accessing {}", service.getClass().getSimpleName());}
}

8.最后,监控问题

我们将写另一个方面来监视关注。 建议如下:

@Aspect
@Component
public class CentralMonitoringHandler {private static Logger monitorLogger = LoggerFactory.getLogger("monitoring");@Around("execution(* xpadro.spring.mvc.*..*Service+.*(..)) && target(service)")public Object logServiceAccess(ProceedingJoinPoint jp, Object service) throws Throwable {long startTime = System.currentTimeMillis();Object result = jp.proceed();long totalTime = System.currentTimeMillis() - startTime;monitorLogger.info("{}|Invocation time {}ms ", service.getClass().getSimpleName(), totalTime);return result;}
}

9.检查最终代码

在将所有交叉问题模块化后,我们的控制器和服务仅包含业务逻辑:

@Controller
public class ClientController {@Autowiredprivate ClientService clientService;@RequestMapping("/getClients")public String getClients(Model model, @RequestParam("id") int id) {Client client = clientService.getClient(id);model.addAttribute("client", client);return "showClient";}	
}@Service("clientService")
public class ClientServiceImpl implements ClientService {@Autowiredprivate ClientRepository clientRepository;@Override@Transactional(readOnly = true)public Client getClient(int id) {return clientRepository.getClient(id);}
}

10,结论

我们已经看到了如何应用面向方面的编程来保持我们的代码整洁,并专注于针对其设计的逻辑。 在使用AOP之前,只需考虑其已知的限制。

参考:在XavierPadró的Blog博客上,从我们的JCG合作伙伴 Xavier Padro 应用面向方面的编程 。

翻译自: https://www.javacodegeeks.com/2014/02/applying-aspect-oriented-programming.html

面向切面编程应用

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

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

相关文章

centos 安装php扩展gd,linux(centos)下为php添加添加GD扩展

yum -y install libjpeglibjpeg-devel libpng libpng-devel freetype freetype-devel 安装依赖库yum -y install libjpeg-devel1.首先切换到php源码目录&#xff1a;/usr/local/php-5.6.29/ext/gd2.利用phpize生成gd扩展文件,/usr/local/php/bin/mipsel-linux-phpize, ls 或者 …

弹簧启动执行器教程

朋友您好&#xff0c;在本教程中&#xff0c;我们将学习弹簧执行器及其所有功能。 1.什么是弹簧执行器&#xff1f; 2.如何在Maven项目或Gradle项目中添加弹簧执行器&#xff1f; 3.创建一个具有Spring Actuator依赖项的Spring Boot项目。 4.使用弹簧执行器端点监视应用程序…

php xls 邮件,PHPMailer发送邮件

PHPMailer是一个封装好的PHP邮件发送类&#xff0c;支持发送HTML内容的电子邮件&#xff0c;以及图片附件&#xff0c;前提要设置好邮件服务器就能实现邮件发送功能。HTML首先我们先放置一个收件箱的输入框和一个发送邮件按钮&#xff1a;收件人&#xff1a;jQuery$(function()…

引导性GCP:带有Google Cloud Pub / Sub的Spring Cloud Stream

我最近在Sprint Central的工程博客上阅读了Josh Long的Bootiful GCP系列 &#xff0c;特别喜欢关于使用Google Cloud的Pub / Sub的第四部分 。 我受到该系列的启发&#xff0c;同时我还在为我的一个新项目评估Spring Cloud Stream。 我以为&#xff0c;我会继续讨论乔希&#x…

jdbc和jdbc驱动_JDBC布尔兼容性列表

jdbc和jdbc驱动有趣的是&#xff0c;布尔类型只是在SQL标准后期才引入&#xff0c;即SQL&#xff1a;1999 。 即使在今天&#xff0c;并非所有数据库本身都支持BOOLEAN或BIT类型。 最重要的是&#xff0c;我们仍然可以在Oracle中等待一段时间。 这是2002年以来关于该主题的“问…

IDE日志分析方法pt。 1个

介绍 我认为大多数软件工程师都了解日志的重要性。 它们已成为软件开发的一部分。 如果无法解决问题&#xff0c;我们尝试在日志中查找原因。 对于一些简单的情况&#xff0c;当错误阻止应用程序打开窗口时&#xff0c;这可能就足够了。 您可以在日志中找到问题&#xff0c;然后…

java运行构建期间出错_构建和运行Java 8支持

java运行构建期间出错尚未提供对Java 8的Eclipse支持。 如果要使用它&#xff0c;则必须构建它。 Eclipsepedia的JDT Core / Java8页面包含有关使用Eclipse Java开发工具 &#xff08;JDT&#xff09;中不断发展的Java 8支持源来设置开发环境的说明。 说明中缺少一些内容&#…

从Commons CLI迁移到picocli

最初于2002年发布的Apache Commons CLI可能是使用最广泛的Java命令行解析器&#xff0c;但是它的API显示了它的年龄。 寻找具有最少样板代码的现代方法的应用可能对picocli感兴趣。 为什么要花麻烦的钱进行迁移&#xff0c;以及如何将基于Commons CLI的应用程序迁移到picocli&a…

QuickBooks和Sage数据导出器

许多中小企业都使用QuickBooks作为其会计模块。 同样&#xff0c;许多公司也使用Sage进行会计处理。 他们中的大多数人在需要从这些系统中导出数据时会遇到问题。 在线提供的许多连接器价格昂贵&#xff0c;无法满足确切的要求。 随附的是一些简短的代码段&#xff0c;这些代码…

php内容缓存输出,PHP使用缓存即时输出内容(output buffering)的方法

PHP使用缓存即时输出内容(output buffering)的方法PHP使用缓存即时输出内容(output buffering)的方法。分享给大家供大家参考。具体如下&#xff1a;$buffer ini_get(output_buffering);echo str_repeat( ,$buffer1); //防止浏览器缓存ob_end_flush(); //关闭缓存for( $i1; $i…

继承能够访问父类私有字段_在单元测试中访问私有字段

继承能够访问父类私有字段首先&#xff0c;让我大声说一下&#xff0c;您需要将代码设计为可测试的&#xff0c;以便通过公共方法测试私有字段。 但是&#xff0c;&#xff08;“ buts”是人们仍在编程而不是计算机本身的原因&#xff0c;所以在这里很高兴&#xff09;有时您想…

甲骨文函数初探

我非常高兴有机会通过Cloud Native Limited Availability Program来测试Oracle功能。 去年&#xff0c;当我上次尝试在Oracle Groundbreaker APAC巡回赛中在Oracle Cloud中运行无服务器功能时&#xff0c;有两种选择。 您可以在虚拟机中运行我自己的Fn服务器&#xff0c;也可以…

spring roo_使用Spring Roo进行概念验证

spring roo在Keyhole工作期间&#xff0c;我参与了许多项目&#xff0c;其中客户要求我们重写旧系统&#xff0c;同时保留其现有数据库。 有时&#xff0c;它有助于快速演示如何使用当前技术来简化开发&#xff0c;测试和维护其代码。 我发现可以创建一个快速示例&#xff08;…

oracle虚拟机怎么装系统,Virtualbox怎么安装系统 VirtualBox虚拟机安装Win8系统教程 (3)...

三、对新建的虚拟机做重要的设定&#xff1a;1、在Oracle VM VirtualBox里面点击下刚才建好的虚拟机&#xff0c;然后点下上面的黄色图标“设置”&#xff0c;或者右键菜单里面点击设置也可以(快捷键是CtrlS)Oracle VM VirtualBox虚拟机设置2、在出来的设置页面里面&#xff0c…

oracle xe gentoo,Oracle在gentoo下安装

补充:解决ORACLE10G安装界面中文乱码问题&#xff0c;修改以下变量使安装界面为英文。export LC_CTYPEen_US.UTF-8以下为原文1.OS:Gentoo-linux-2.6.23-rc5Oracle:Oracle Database 10g Release 2 (10.2.0.1.0) for Linux x86下载地址&#xff1a;2.使用管理员账户建立Oracle用户…

JMetro 5.2版发布

再一次问好 JMetro的新更新刚刚发布。 添加了两种新的控件样式&#xff1a;“标题窗格”和“手风琴”。 此外&#xff0c;还对现有样式和错误修复进行了调整。 最终&#xff0c;JMetro现在也可以通过Maven Central获得。 在本文中&#xff0c;我将详细介绍刚刚发布的JMetro 5…

matlab处理svm的数据,SVM-GUI 使用支持向量机(SVM)算法进行处理数据,提取特征参数,并通过MATLAB界面显示相关数 238万源代码下载- www.pudn.com...

文件名称: SVM-GUI下载收藏√ [5 4 3 2 1 ]开发工具: matlab文件大小: 231 KB上传时间: 2014-05-13下载次数: 13提 供 者: 幽灵详细说明&#xff1a;使用支持向量机(SVM)算法进行处理数据&#xff0c;提取特征参数&#xff0c;并通过MATLAB界面显示相关数据-Using Support…

mockito_Eclipse的Mockito模板

mockito有时候&#xff0c;我想念树林里的树木-那是一段令人不安的长时间。 我最近才再次意识到这一点&#xff0c;在无数次中键入了一个更详细的模仿表达式之一。 有问题的语句是一个doAnswer(Answer)构造&#xff0c;使用涉及到的静态导入和泛型代码进行编码总是很麻烦。 尽…

linux系统运行powerbi,使用 Power BI 服务 - Power BI | Microsoft Docs

快速入门 - 使用 Power BI 服Quickstart - Getting around in Power BI service10/12/2020本文内容备注Power BI 正在转换为新外观&#xff0c;文档中的某些图像可能与服务中显示的图像不匹配。Power BI is moving to a new look, and some images in the documentation may no…

JMetro版本4.8已发布

再一次问好&#xff01; JMetro Java 4.8版JavaFX主题刚刚发布。 我们即将接近下一个主要版本的版本5.0。 这是已经过彻底改造的旧样式&#xff1a; 日期选择器 树视图 以及经过调整或更改了CSS结构的旧版本&#xff1a; 表格检视 列表显示 组合框 评级控制 4.8版详细…