用方面清理代码

在我以前的文章中,我描述了字母转换,并且提到了我们使用AspectJ解决了该任务,但是我没有提及AspectJ的工作原理以及一般性的方面。 因此,在接下来的几行中,我将解释:
  • 什么是面向方面的编程,为什么我们需要它
  • 什么是AspectJ
  • 将AspectJ与Spring结合使用(配置AspectJ和spring一起工作)
  • 我将解释以前帖子中示例的各个方面。

什么是面向方面的编程以及我们为什么需要它

在软件开发过程中,我们可以使用不同的编程范例,例如OOP(面向对象编程)或POP(面向过程编程)。
今天,我们大多数人在软件开发过程中使用面向对象的编程方法来解决现实生活中的问题。

但是在我们的工作中,我们经常遇到一些代码,这些代码贯穿我们的代码库,破坏了其模块性并使它变得肮脏。

这部分代码通常没有业务价值,但是我们需要它们来解决问题。
例如,我们可以看一下数据库事务。

事务对于我们的软件非常重要,因为它们要注意数据的一致性。 启动和处理事务的代码对于我们的应用程序非常重要,但是它用于技术性工作(启动,提交和回滚事务)。 这些东西使得很难理解代码的真正含义(查看代码的实际业务价值)。

当然,我不会在如何使用方面处理事务方面做任何示例,因为有很多框架会代替我们来处理事务。 我刚刚提到了事务,因为您可能知道如何使用简单的JDBC API将数据插入数据库。

因此,为了使代码更整洁,我们将使用设计模式,这是解决问题的好方法。 但是有时候使用设计模式也不会导致我们找到简单的解决方案,而我们大多数人会诉诸于更简单的解决方案,从而产生“肮脏”的代码。

在这种情况下,我们应该有机会采用面向方面的方法来解决问题。 在考虑AOP时,我们不应该考虑对我们来说是全新的东西,而应该将AOP视为对OOP的补充。 AOP可以简化代码模块化,使代码更整洁,并使我们更容易,更快地了解应用程序的某些部分应该做什么。

AOP引入了一些新概念,这将使我们更容易进行代码调制。 如果我们想有效地使用Aspects,我们需要了解其基本原理和术语。
当我们开始使用AOP时,我们将遇到一个新的终端:

  • 横切关注点是应该在单独的模块中移动的代码(即用于处理交易的代码)。
  • 方面,它是包含关注点的模块。
  • 切入点,我们可以将其视为指针,它将指示何时应运行相应的代码
  • 建议,它包含一个代码,当到达某个连接点时应运行该代码。
  • 内部类型声明,允许修改类结构。
  • 方面编织是协调与系统其余部分集成的机制。

我将在示例中最后说明它们是什么以及如何使用它们。

什么是AspectJ

AspectJ是Java编程语言的扩展,它允许在Java编程语言中使用AOP概念。

使用AspectJ时,无需在现有代码中进行任何更改。

AspectJ使用称为Aspect的新结构扩展了Java,在AspectJ 5之后,您可以使用基于注释的开发样式。

AspectJ和Spring

Spring框架已经提供了自己的AOP实现。 Spring AOP是比AspectJ更简单的解决方案,但它不如AspectJ强大。 因此,如果要在Spring应用程序中使用方面,在选择AspectJ进行工作之前,应该熟悉Spring AOP的可能性。

在我们看到使用Aspect的示例之前,我将向您展示如何将AspectJ与Spring集成以及如何配置Tomcat以使其能够在Spring中运行AspectJ应用程序。 在此示例中,我使用了方面的LTW(加载时间编织)。

因此,我将首先从Spring开始解释如何做。 很简单,只需在应用程序配置文件中添加下一行:

<context:load-time-weaver aspectj-weaving="autodetect"/>

这就是弹簧配置所要做的全部工作。

下一步是Tomcat的配置。 我们需要为应用程序定义新的类加载器。 该类加载器需要能够进行加载时编织,因此我们使用:

<loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" />

加载程序必须在Tomcat类路径中,然后才能使用。
当然,为了使此工作有效,我们需要创建aop.xml文件。 该文件包含将在类转换过程中由类加载器使用的指令。 这是我用于字母转换的aop.xml文件的示例。

<aspectj><weaver options="-Xset:weaveJavaxPackages=true"><!-- only weave classes in our application-specific packages --><include within="ba.codecentric.medica.model.*" /><include within="ba.codecentric.medica..*.service.*" /><include within="ba.codecentric.medica.controller..*" /><include within="ba.codecentric.medica.utils.ModelMapper" /><include within="ba.codecentric.medica.utils.RedirectHelper" /><include within="ba.codecentric.medica.aop.aspect.CharacterConvertionAspect" /><include within="ba.codecentric.medica.security.UserAuthenticationProvider" /><include within="ba.codecentric.medica.wraper.MedicaRequestWrapper"/></weaver><aspects><!-- weave in just this aspect --><aspect name="ba.codecentric.medica.aop.aspect.CharacterConversionAspect" /></aspects>
</aspectj>

对于愿意尝试AspectJ的所有人来说,最后一个xml文件最为有趣。 它指示AspectJ编织过程。
编织器部分包含有关应编织的信息。 因此,此文件将在其中包含所有类:

  • ba.codecentric.medica.model。*
  • ba.codecentric.medica .. *。service。*
  • ba.codecentric.medica.controller .. *
  • ba.codecentric.medica.utils.ModelMapper
  • ba.codecentric.medica.utils.RedirectHelper
  • ba.codecentric.medica.aop.aspect.CharacterConvertionAspect
  • ba.codecentric.medica.security.UserAuthenticationProvider
  • ba.codecentric.medica.wraper.MedicaRequestWrapper

因此,第一行包括模型包中的所有类。 第二个类包括所有类,它们是ba.codecentric.medica包(即ba.codecentric.medica.hospitalisation.service)内的service子包的一部分。 第三个包括控制器组件下方的所有内容。 其余各行包括指定的类。
选项属性定义在编织过程中应使用的附加选项。 因此,在此示例中-Xset:weaveJavaxPackages = true指示AspectJ也编织Java包。 方面部分包含将在编织过程中使用的方面的列表。 有关使用xml配置的更多信息,请参见AspectJ文档 。

使用示例AspectJ


我更喜欢使用注释,因此下一个示例将向您展示如何将AspectJ与注释一起使用。 从AspectJ 5版本开始,可以使用AspectJ进行注释驱动的编程。这是一些完整方面的代码,其中包含用于字母转换的注意事项。

package ba.codecentric.medica.aop.aspect;import java.util.List;
import java.util.Map;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;import ba.codecentric.medica.utils.CharacterConverter;
import ba.codecentric.medica.utils.ContextHelper;
import ba.codecentric.medica.utils.LanguageHelper;/*** Aspect used for transformation characters from one alphabet to another. * * @author igor**/
@Aspect
public class CharacterConvertionAspect {private static Log LOG = LogFactory.getLog(CharacterConvertionAspect.class);public int getConvertTo() {return getLanguageHelper().getConvertTo();}protected LanguageHelper getLanguageHelper() {return ContextHelper.getBean("languageHelper");}public CharacterConvertionAspect() {LOG.info("Character converter aspect created");}@SuppressWarnings("rawtypes")@Around("execution(public java.lang.String ba.codecentric.medica.model..*.get*(..)) && !cflow(execution(* ba.codecentric.medica.controller..*.*(..))) && !cflow(execution(public void ba.codecentric.medica..*.service..*.*(..))) && !cflow(execution(* ba.codecentric.medica.security.UserAuthenticationProvider.*(..)))")public Object convertCharacters(ProceedingJoinPoint pjp) throws Throwable {LOG.info("Character conversion trigered");Object value = pjp.proceed();if (value instanceof String) {LOG.info("Convert:" + value);Signature signature = pjp.getSignature();Class type = signature.getDeclaringType();String methodName = signature.getName();Map<Class, List<string&lgt;&lgt; skipConvertionMap = getBlackList();if(skipConvertionMap.containsKey(type)){List<string&lgt; list = skipConvertionMap.get(type);if(list == null || list.contains(methodName)){LOG.info("Value will not be converted because it is on blacklist");return value;}}return getConverter().convertCharacters((String) value, getConvertTo());}LOG.info("Convertion will not be performed (" + value + ")");return value;}@Around("execution(public void ba.codecentric.medica.model..*.set*(java.lang.String))")public Object convertCharactersToLat(ProceedingJoinPoint pjp) throws Throwable {Object value = pjp.getArgs()[0];LOG.info("Converting value:" + value + ", before persisting");if (value instanceof String){value= getConverter().convertCharacters((String)value, CharacterConverter.TO_LAT);}return pjp.proceed(new Object[]{value});}/*** Convert parameter to Latin alphabet* * @param pjp* @return* @throws Throwable*/@Around("execution(public * ba.codecentric.medica.wraper.MedicaRequestWrapper.getParameter*(..))")public Object convertParametersToLat(ProceedingJoinPoint pjp) throws Throwable {Object value = pjp.proceed();return getConverter().convert(value, CharacterConverter.TO_LAT);}/*** If result of the invocation is String, it should be converted to chosen alphabet.* * @param jp* @return converted value* @throws Throwable*/@Around("execution(* ba.codecentric.medica.controller..*.*(..))")public Object procedWithControllerInvocation(ProceedingJoinPoint jp) throws Throwable {Object value = jp.proceed();return getConverter().convert(value, getConvertTo());}public CharacterConverter getConverter() {return ContextHelper.getBean("characterConverter");}@SuppressWarnings("rawtypes")public Map<Class,List<string&lgt;&lgt; getBlackList(){return ContextHelper.getBean("blackList");}}

首先,我们可以看到该类使用@Aspect注释进行了注释。 这表明此类实际上是一个方面。 Aspect是一种包含类似横切关注点的构造。 因此,我们可以将其视为包含交叉代码的模块,并定义何时使用代码以及如何使用。

@Around("execution(public void ba.codecentric.medica.model..*.set*(java.lang.String))")
public Object convertCharactersToLat(ProceedingJoinPoint pjp) throws Throwable {Object value = pjp.getArgs()[0];LOG.debug("Converting value:" + value + ", before persisting");if (value instanceof String) {value = getConverter().convertCharacters((String) value, CharacterConverter.TO_LAT);}return pjp.proceed(new Object[] { value });
}

这是一种使用@Around注释进行注释的方法。 周围注释用于表示周围建议。 我已经提到过,建议是包含跨领域代码的地方。 在此示例中,我仅使用了“周围”建议,但是除了在返回之前,之后,之后和引发建议之后还有其他建议。 除了周围的所有建议,都不应有返回值。 注释周围的内容定义了何时编织建议中的代码。 当我们定义切入点时,也可以做到这一点。 在此示例中,我没有使用切入点来定义连接点,因为它是简单的方面。 使用切入点注释,您可以定义真正的鲁棒连接点。 在这种情况下,将在设置只有一个类型为String的参数的实体bean的值期间执行建议。
在上面的示例中,ProcidingJoinPoint pjp提供了连接点,因此在此示例中,它是实体bean的setter方法。 发送到实体设置器方法的对象的值将首先转换,然后将使用转换后的值调用设置器方法。 如果我不使用方面,我的代码可能如下所示:

public void setJmbg(String jmbg) {this.jmbg = getConverter().convertCharacters(jmbg, CharacterConverter.TO_LAT);
}

我已经说过,在此示例中,我使用LTW。 因此,在接下来的几行中,我将尝试简要地解释编织过程。 编织是其中类以定义的方面进行转换的过程。 在下一张图片中,您可以看到编织过程的图示。

为了更好地理解编织,在这种情况下,可以将其视为围绕调用方法的代码注入。

结论


因此,在此示例中,我仅介绍了使用AspectJ进行方面编程的一些基本原理。 这方面帮助我保持了代码的整洁。 使用方面的结果是跨界代码与实际业务价值代码的清晰分离。 控制器,服务和实体Bean保持整洁,并且将技术代码提取到单独的模块中,使您可以更轻松地理解和维护代码。 有关定义切入点和AspectJ项目常规的更多详细信息,您可以在项目页面上看到。

祝您编程愉快,别忘了分享!

参考:在Igor Madjeric博客上,我们的JCG合作伙伴 Igor Madjeric 提供了一些方面干净的代码 。


翻译自: https://www.javacodegeeks.com/2012/10/clean-code-with-aspects.html

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

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

相关文章

java前三章总结

Java前三章总结 第一章&#xff1a;1.Java都有什么东西&#xff1f; Jdk&#xff08;java开发工具包&#xff09;包括 Jre&#xff08;Java运行环境&#xff09;---------->jvm&#xff08;Java虚拟机&#xff09; 应用&#xff08;javac&#xff09; Java API和一些常用的j…

原型 - 实现自己的jQuery

每个第一次使用jq的开发者都感到惊叹,jq的$太神奇了,究竟是怎么做到的使用$控制dom 赞叹前人之余,探究其本源才是前端开发者应该做的事,社区常常说,不要重复造轮子, 可是啊,连轮子都造不出来,又怎么去了解在什么环境下用什么轮子,怎么样才可以造成更加优秀的轮子, 不同阶段对…

html 用svg缩放拉伸,html – 拉伸SVG以适应其父级的100%高度和宽度

如果您对另一种选择开放,您可以使用纯CSS创建形状.它不会像SVG那样整洁,但它会响应&#xff1a;* {box-sizing:border-box;}.box {margin:40px;padding:0 10px;max-width:200px;display:inline-block;vertical-align:top;border-right:2px solid green;border-left:2px solid g…

server.transfer 无法跳转页面_H5 腾讯地图无法导航

uni-app 打包H5腾讯地图无法导航前言&#xff1a;最近几天用uni-app开发安卓和iOS应用&#xff0c;打包成APP安装包后&#xff0c;APP内做地图导航没有问题&#xff0c;APP内使用的是高德地图&#xff1b;但是打包成为H5页面后&#xff0c;运行在微信内置浏览器或者运行在第三方…

打破PermGen神话

在我的最新文章中&#xff0c;我解释了可能导致java.lang.OutOfMemoryError&#xff1a;PermGen空间崩溃的原因 。 现在该讨论该问题的可能解决方案了。 或者&#xff0c;更确切地说&#xff0c;是关于互联网对可能解决方案的建议。 不幸的是&#xff0c;我只能说&#xff0c;我…

Linux获取当前年月日后缀精确到微秒,例如2017-05-06T23:57:07.713171

代码如下&#xff1a;详细见注释 #include <stdio.h> #include <string.h> #include <time.h> #include <sys/time.h>int main() {struct timeval start;struct tm *local_time NULL;static char str_time[100];char ms[16];gettimeofday( &start…

PhiloGL学习(5)——神说要有光,便有了光

前言 上一篇文章中介绍了如何创建三维对象及加载皮肤&#xff0c;本文为大家介绍如何为场景添加光源。 一、 原理分析 光在任何地方都是非常重要的&#xff0c;无论在哪里都说是要发光发热&#xff0c;光和热也是分不开的。光线分为点光源和线光源&#xff0c;所谓点光源和线光…

android 弹出弹框2秒消失_基于HTML5 Canvas 实现弹出框

前言用户鼠标移入时&#xff0c;有弹出框出现&#xff0c;这样的需求很常见。这在处理 HTML 元素实现时简单&#xff0c;但是如果是对 HTML5 Canvas 构成的图形进行处理&#xff0c;这种方法不再适用&#xff0c;因为 Canvas 使用的是另外一套机制&#xff0c;无论在 Canvas 上…

【CSS】小妙招,各种问题总结方法处理

1.实现div文字溢出自动省略号截取 overflow:hidden; /*超过部分不显示*/       text-overflow:ellipsis; /*超过部分用点点表示*/       white-space:nowrap;/*不换行*/ 2.规定行数的截取效果 text-overflow: ellipsis; /*有些示例里需要定义该属性&#xff0c…

Java2Days 2012:Java EE

Java2Days会议是东欧的主要活动&#xff0c;目的是介绍Java开发的最新趋势。 今年&#xff0c;该活动于10月25日至26日在保加利亚的索非亚举行。 我在那里&#xff0c;并有机会与一些SAP的同事一起品尝了一些最新的Java&#xff0c;云和移动内容&#xff0c;这些内容已直接发送…

html5布局总结,HTML5网页布局的总结

可以通过 和 将 html 元素组合起来。html 块元素大多数 html 元素被定义为块级元素或内联元素。编者注&#xff1a;“块级元素”译为 block level element&#xff0c;“内联元素”译为 inline element。块级元素在显示时&#xff0c;通常会以新行来开始(和结束)。例子&#x…

c++ 优先队列_C/C++数据结构:队列结构最全解析!带你零基础入门队列结构

前言上一章节针对于C语言栈结构做了解析&#xff0c;不清楚的可以回顾一下。本章节主要针对于C语言的基础数据结构队列做以解析。数据结构之队列队列是一种特殊的 线性表 &#xff0c;特殊之处在于它只允许在表的前端&#xff08;front&#xff09;进行删除操作&#xff0c;而在…

bit-map再显身手:test.txt中有42亿个无符号整数, 求不存在于test.txt中的最小无符号整数。限制: 可用内存为600MB....

先看看这个题目&#xff1a;test.txt中有42亿个无符号整数&#xff0c; 求不存在于test.txt中的最小无符号整数. 限制&#xff1a; 可用内存为600MB. 又是大数据。 看到42亿&#xff0c; 有灵感没&#xff1f; 要知道&#xff0c; 2的32次方就是42亿多一点点啊。42亿个无符号…

周期均方根和有效值的区别_黑猪肉和白猪肉有啥区别?

为啥散养黑猪肉的价格要比白猪贵很多?这其中的原因不看不知道!市面上的散养黑猪肉通常要比白猪肉贵很多&#xff0c;但是仍有不少人喜欢买黑猪肉回家吃&#xff0c;散养黑猪肉和白猪肉不仅仅是口感上有所差距&#xff0c;其价值差距体现在很多方面&#xff0c;接下来小编就和大…

BZOJ1734: [Usaco2005 Feb]Aggressive cows 愤怒的牛

【传送门&#xff1a;BZOJ1734】 简要题意&#xff1a; 约翰有N 间牛棚&#xff0c;这些牛棚坐落在一条直线上&#xff0c;第i 间牛棚位于坐标Xi 的位置。他要把C 头 奶牛安排在这些牛棚里。每间牛棚最多可以放一头奶牛&#xff0c;也可以空着。这些奶牛的脾气都很暴燥&#xf…

CSS基础范例

1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset"UTF-8">5 <title>Title</title>6 <style>7 *{8 margin: 0; /*重置*/9 padding: 0…

测试环境搭建流程_前端构建 DevOps 搭建 DevOps 基础平台(中)

前言搭建基础平台搭建上篇的时候的时候&#xff0c;已经介绍过了项目流程设计、数据库搭建、jwt 登录等模块。此篇我们介绍分支管理设计及其他的基础模块。后端模块DevOps - Gitlab Api使用(已完成&#xff0c;点击跳转)DevOps - 搭建 DevOps 基础平台(已完成 50%)基础平台搭建…

什么是PermGen泄漏?

接下来是对Java应用程序中特定类型的内存问题的实用介绍。 即–我们将分析导致java.lang.OutOfMemoryError&#xff1a;PermGen空间的错误 堆栈跟踪中的症状。 首先&#xff0c;我们将介绍理解该主题所需的核心概念&#xff0c;并说明什么是对象&#xff0c;类&#xff0c;类…

html浮动炫酷样式,jQuery和CSS3炫酷表单浮动标签特效

这是一款炫酷的jQuery和CSS3表单浮动标签特效。浮动标签是指输入框中的文字或占位文本在输入框聚焦的时候&#xff0c;以动画的方式浮动到指定的地方。浮动标签特效是一种新颖时尚的动画特效&#xff0c;不仅效果很酷&#xff0c;而且能以明确的方式提示用户该输入框应该填写上…

rto净化效率计算公式_全面剖析 石油化工行业RTO蓄热式焚烧炉的优势要素

在我国的国民经济发展中&#xff0c;石油化工产业是重要的能源基础工业&#xff0c;但是废气的治理问题一直困扰着许多企业。直到RTO蓄热式焚烧炉的面世&#xff0c;为石油化工行业的废气治理带来了新希望。如今&#xff0c;有机废气治理工作越来越受到广泛重视&#xff0c;传统…