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

面向切面编程应用

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,一经查实,立即删除!

相关文章

【渝粤题库】陕西师范大学201541 合同法作业

《合同法》作业 一、单项选择题 李某将自己房屋租给张某使用&#xff0c;租给一段时间后&#xff0c;双方经过商议达成房屋买卖合同&#xff0c;则该房屋的所有权发生转移的特别生效要件是下列哪种行为&#xff1f; A.占有改定 B.简易交付 C.登记 D.公证 2&#xff0e;甲念高三…

php 字符串索引值,PHP:字符串索引不一致?

我创建了一个函数,该函数从硬编码的单词列表中随机生成一个短语.我有一个函数get_words(),该函数具有一串硬编码的单词,将其转换成一个数组,然后重新排列并返回.get_words()由generate_random_phrase()调用,它会反复遍历get_words()n次,并且在每次迭代时,将n个单词连接到最终的…

【渝粤题库】陕西师范大学202013 民法专论 作业

《民法专论》作业 一、单选题 1、为了保护民事主体的合法权益&#xff0c;调整民事关系&#xff0c;维护社会和经济秩序&#xff0c;适应 &#xff0c;弘扬社会主义核心价值观&#xff0c;根据宪法&#xff0c;制定本法。下划线处应填&#xff08;  &#xff09; A. 社会主义…

使用JUnit5对DynamoDB应用程序进行单元测试

在之前的文章中&#xff0c;我描述了新的Java 2 AWS SDK&#xff0c;它为调用不同AWS服务的Java客户端提供了非阻塞IO支持。 在本文中&#xff0c;我将介绍一种用于单元测试AWS DynamoDB调用的方法。 有几种方法可以启动DynamoDB的本地版本– 1. AWS提供了一个DynamoDB本地 …

【渝粤题库】陕西师范大学202421 教育管理心理学 作业 (专升本)

《教育管理心理学》作业 一、名词解释 人际知觉 2.态度 3&#xff0e;内化 4&#xff0e;社会知觉角色知觉 6&#xff0e;晕轮效应 7&#xff0e;激励因素 8&#xff0e;经济人退化 10&#xff0e;首因效应 11&#xff0e;激励 12&#xff0e;需要 13.保健因素 14. 挫折 15.制…

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 或者 …

【渝粤题库】陕西师范大学209013 计量经济学 作业

一、名词解释 1&#xff0e;偏回归系数 2&#xff0e;异方差性 3&#xff0e;虚拟变量 4&#xff0e;间接最小二乘法 5&#xff0e;调整的多元可决系数 6&#xff0e;序列相关性 7&#xff0e;滞后变量 8&#xff0e;行为方程 9&#xff0e;受约束回归 10&#xff0e;多重共线…

【渝粤题库】陕西师范大学210023 学前儿童社会教育 作业(专升本)

《学前儿童社会教育》作业 一、单选题 1&#xff0e;我国有关儿童社会性发展研究得到迅速发展的年代是&#xff08; &#xff09; A&#xff0e;20世纪30年代 B&#xff0e;20世纪70年代 C&#xff0e;20世纪80年代 D.&#xff0e;20世纪90年代 2&#xff0e;安斯沃思将婴幼儿的…

php numeric乘法,PHP is_numeric()用法及代码示例

is_numeric()函数是PHP中的内置函数&#xff0c;用于检查传入函数中作为参数的变量是数字还是数字字符串。该函数返回一个布尔值。用法:bool is_numeric ( $var )参数&#xff1a;该函数接受一个必须的单个参数&#xff0c;如下所述&#xff1a;$var:此输入参数是变量&#xff…

【渝粤题库】陕西师范大学292161社会保障概论 作业(专升本)

《社会保障概论》作业 一、填空题 1、英国政府于1601年颁布了 &#xff0c;标志着社会保障制度的萌芽。 2、 是社会保障制度的核心部分&#xff0c; 是社会保障的最高层次&#xff1b; 是社会保障最后一道防线。 3、就业保障制度包括&#xff1a; 、 、 三方面内容。 4、工伤保…

jooq权限配置_将jOOQ与Spring结合使用:配置

jooq权限配置我遇到了由ORM引起的性能问题。 尽管我不得不承认大多数这些问题确实是由您造成的&#xff0c;但是我开始认为在只读操作中使用ORM是不值得的。 我开始寻找实现这些操作的替代方法。 这就是我遇到jOOQ的方式 &#xff0c;它指出&#xff1a; jOOQ从您的数据库生…

【渝粤题库】陕西师范大学600001物理化学(上) 作业(专升本)

《物理化学&#xff08;上&#xff09;》作业 一.单选题 1.下列物理量中属于强度性质的是 A. H B. S C. p D. G 2.298.2K时&#xff0c;1mol的氧气&#xff08;可视为理想气体&#xff09;经等温可逆膨胀后&#xff0c;体积胀大10倍&#xff0c;对于该过程来说&#xff0c; 其Δ…

employee.java,Java基础系列(六):对象与类(上)

概述类(class)是构造对象的模板。由类构造对象的过程称为创建类的实例。封装从形式上看&#xff0c;封装是将数据和行为组合在一个包中&#xff0c;并对对象的使用者隐藏了数据的实现方式。对象中的数据称为实例域&#xff0c;而操纵数据的过程称之为方法。对于每个特定的类实例…

【渝粤题库】陕西师范大学800007 地理信息系统

《地理信息系统》作业 一&#xff0e;名词解释 &#xff11;&#xff0e;TIN       2 .缓冲区分析 &#xff13;&#xff0e;元数据 &#xff14;. 地理信息系统 &#xff15;&#xff0e;空间数据库  &#xff16;&#xff0e;拓扑关系 &#xff17;&#xff0e;矢量结…

国家开放大学2021春1080工程数学(本)题目

教育 教育 试卷代号&#xff1a; 1080 2021年春季学期期末统一考试 工程数学&#xff08;本&#xff09; 试题 2021年7月 一、单项选择题&#xff08;每小题3分&#xff0c;共15分&#xff09; 1.设方阵可逆&#xff0c;则下列命题中不正确的是( ). A. B.线性方程组必有非零解…

弹簧启动执行器教程

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

matlab 大于并且小于,Matlab:将大于(小于)1(-1)的元素转换为1(-1)的序列

更新&#xff1a;我做了一些测试,Jonas的解决方案对于一系列不同大小的输入向量来说是最快的.特别是,正如angainor指出的那样,解决方案可以很好地扩展到大尺寸 – 这是一个重要的测试,因为通常是大尺寸的问题促使我们在SO上提出这些问题.感谢Jonas和tmpearce的解决方案 – 基于…

matlab 里try用法,matlab在整个程序(全局)中使用try-catch来报告错误

我的matlab程序是一个多窗口程序化GUI。我已经实现了一个报告系统&#xff0c;所以当遇到错误时&#xff0c;它会调用我编写的函数generateReport.m&#xff0c;它发送一个带有一些日志和状态信息的电子邮件&#xff0c;然后继续执行。为了实现这一点&#xff0c;我在每个单独的…

【渝粤题库】陕西师范大学200741概率论与数理统计作业(高起本、专升本)

《概率论与数理统计》作业 一、填空题 1&#xff0e;设有两门高射炮&#xff0c;每一门击中飞机的概率都是0.6&#xff0c;则同时发射一发炮弹而击中飞机的概率为   .若有一架敌机入侵领空&#xff0c;欲以99%以上的概率及中它&#xff0c;至少需 &#xff3f;&#xff3f;&…

php xls 邮件,PHPMailer发送邮件

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