用方面清理代碼

在我以前的文章中,我描述了字母轉換,并且提到了我們使用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.pswp.cn/news/370796.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370796.shtml
英文地址,請注明出處:http://en.pswp.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;傳統…