有段日子沒有總結東西了,因為最近確實有點忙,一直在忙於hadoop集群的搭建,磕磕碰碰現在勉強算是能呼吸了,因為這都是在自己的PC上,資源確實有點緊張(搭建過程后期奉上),今天難得大家都有空(哈哈哈~~~),給各位總結一下Java開發猿人盡皆知的Spring框架它的核心組件——AOP(面向切面編程)。
老規矩,首先給各位說說它吧。AOP作為面向切面編程,是一種橫向抽取的思想體現,不錯,有了"橫向切"這個概念呢,我們就應該會聯想到之后的橫切面、切入點,接着你有可能就會閉上眼睛想入非非,但是哥們你千萬不要走歪,咱們現在討論的是Java領域的切面編程,啊哈哈哈~好了,既然是面向切面編程,那么就避免不了"切",都知道,咱們的項目都會從web層到service層到dao層依次執行,既然是切,那么就會從某個層和某個層之間切開,接着就會做一些我們想做的事兒。反正大概的意思就是我所理解的切面編程,譬如切面編程的底層采用動態代理實現,在Spring框架中具體是如何執行的,我就不在這兒啰嗦了,因為這個點兒我也對源碼不是理解的那么透徹,一直在學習的路上,等后期吃到點兒精華再回來給各位完善,下面我就會將我使用2中方式實現AOP切面編程的案例給各位共享一下。
小小一張圖,請給位笑納:
Spring框架的AOP切面編程分為倆種:注解式開發和XML配置式開發。
項目結構圖:
AOP注解式開發:
首先我們使用注解式開發,最重要的一點就是能夠讓這些注解生效,何為生效?就是能夠讓它們活着看到spring框架的臨幸,為什么說這個不起眼的問題呢,我在昨天使用注解都開發完了,但是怎么也執行不到切面上的方法,說白了就是注解沒有掃描到,按理論說,切面都是會出現在service層前后,也就是說一般切面會作用在service層上,比如:在更新操作前進行權限校驗、在檢索操作時記錄檢索時長等等。那么我們通常使用spring的容器來掃描這些注解,但是在一些springMVC和spring共存的項目中,我們還不得不注意一下它們父子容器的關系,千萬不要認為父子容器和諧共存,和諧共事【這里打個廣告:有關父子容器的問題,請參考http://www.cnblogs.com/1315925303zxz/p/7211037.html】。我這里掃描切面是由spring容器完成的,因為我的切面類都在service層中了,所以我的切面組件的注解是由父容器spring的配置文件掃描的:
1、開啟AOP注解解析器:
1 <!-- 【啟動AOP的注解解析器】(基於注解方式必須添加該注解解析器) --> 2 <aop:aspectj-autoproxy/>
2、實現注解切面編程,附:切入點表達式,AOP切入點表達式的書寫格式: 方法返回值 完整包名.類名.方法名(參數)。 注:如果方法返回值和參數類型不限則可以使用*代替,如果以什么什么開頭的方法也可以使用*代替,就如我們配置spring管理事務的傳播行為雷同。涉及到的AOP的通知類型,在第二種XML配置方式中會詳細介紹,哥們兒別停繼續看着。
1 @Component 2 @Aspect //聲明這是一個切面類 3 public class SelecctAop { 4 5 public static final String REGEX_IP_ADDR = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}"; 6 7 private Date startDate = null; //專門用於存放開始時間 8 9 /** 10 * 定義一個切入點 11 */ 12 @Pointcut("execution(* cn.base.service.*.find*(..))") 13 private void selectPointcut(){} 14 15 /** 16 * 檢索開始前的時間記錄 17 * @return 18 * @throws Exception 19 */ 20 @Before("selectPointcut()") //通知類型 21 public void startTime() throws Exception{ 22 String hostAddress = InetAddress.getLocalHost().getHostAddress(); //獲取操作用戶的IP地址 23 boolean isLegal = hostAddress.matches(REGEX_IP_ADDR); //驗證IP地址 24 if(StringUtil.isNullOrBlank(hostAddress) && !isLegal){ 25 //如果IP地址為空並且IP地址不合法 26 System.err.println("=============警告:非法用戶操作=============="); 27 } 28 startDate = DateTimeUtils.getCurrentDate("yyyy-MM-dd HH:mm:ss"); //開始時間 29 System.err.println(startDate+"【開始】==="+hostAddress+"用戶開始操作"); 30 } 31 32 /** 33 * 檢索結束后的時間記錄、共計操作時長 34 * @throws Exception 35 */ 36 @After("selectPointcut()") //通知類型 37 public void timeConsuming() throws Exception{ 38 String hostAddress = InetAddress.getLocalHost().getHostAddress(); //獲取操作用戶的IP地址 39 boolean isLegal = hostAddress.matches(REGEX_IP_ADDR); //驗證IP地址 40 if(StringUtil.isNullOrBlank(hostAddress) && !isLegal){ 41 //如果IP地址為空並且IP地址不合法 42 System.err.println("=============警告:非法用戶操作=============="); 43 } 44 Date endDate = DateTimeUtils.getCurrentDate("yyyy-MM-dd HH:mm:ss"); //結束時間 45 System.err.println(endDate+"【終止】==="+hostAddress+"用戶結束操作"); 46 long startTime = startDate.getTime(); 47 long endTime = endDate.getTime(); 48 long time = endTime - startTime; 49 System.err.println("================【共計耗時:" + time+ "】====================="); 50 } 51 52 53 public static void main(String[] args) { 54 55 } 56 57 }
3、只要你訪問調用了service層中檢索操作的方法,就會觸發切面上的方法,我這里是只要用戶進行檢索操作,就會實時記錄該次檢索操作的檢索時長。
4、效果如圖:
XML配置式開發:
這種方式相對來說比較原始一點兒,就是通過在spring的核心配置文件中進行配置實現AOP切面編程,就是通過將切面類交由spring容器管理,然后通過spring容器的配置將切面類作用與相關業務方法上。
1、更新操作的切面類:
1 package cn.base.service.aspect; 2 3 import java.net.InetAddress; 4 import java.net.UnknownHostException; 5 import com.zxz.utils.DateTimeUtils; 6 import com.zxz.utils.StringUtil; 7 8 /** 9 * 更新操作切面類:執行刪除、修改、保存操作時需配置的切面類。[基於XML配置方式實現] 10 * @author zxz 11 */ 12 13 public class UpdateAop { 14 15 public static final String REGEX_IP_ADDR = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}"; 16 17 /** 18 * 用戶進行更新操作之前的IP記錄 19 */ 20 public void recordIP(){ 21 String hostAddress = ""; 22 try { 23 hostAddress = InetAddress.getLocalHost().getHostAddress(); //獲取操作用戶的IP地址 24 boolean isLegal = hostAddress.matches(REGEX_IP_ADDR); //驗證IP地址 25 if(StringUtil.isNullOrBlank(hostAddress) && !isLegal){ 26 //如果IP地址為空並且IP地址不合法 27 System.err.println("=============警告:非法用戶操作=============="); 28 } 29 } catch (UnknownHostException e) { 30 e.printStackTrace(); 31 } 32 System.err.println("【==="+DateTimeUtils.getCurrentMsLocal() + "---IP為:" + hostAddress + "進行了更新操作。===】"); 33 } 34 35 public static void main(String[] args) throws Exception { 36 // String hostAddress = InetAddress.getLocalHost().getHostAddress(); 37 // System.out.println(hostAddress); 38 // System.out.println(hostAddress.matches(REGEX_IP_ADDR)); 39 } 40 41 }
2、通過spring的配置實現切面編程:
1 <!-- 配置更新切面類 --> 2 <bean id="updateAop" class="cn.base.service.aspect.UpdateAop"/> 3 4 <!-- spring的aop配置(基於XML方式的) --> 5 <aop:config> 6 <!-- 配置切入點: 7 AOP切入點表達式的書寫格式: 方法返回值 完整包名.類名.方法名(參數)。 注:如果方法返回值和參數類型不限則可以使用*代替。 8 --> 9 <aop:pointcut expression="execution(* cn.base.service.*.delete*(..))" id="updatePointcut"/> 10 <!-- 配置切面 --> 11 <aop:aspect ref="updateAop"> 12 <!-- 切面的通知類型: 13 AOP的通知類型有: 14 1、前置通知【before】在方法執行之前進行增強,獲得切入點信息。 15 2、后置通知【after】在方法執行之后進行增強,獲得方法的返回值。 16 3、環繞通知【around】在方法執行前后進行增強,[阻止]目標方法執行。 17 4、異常拋出通知【after-throwing】在方法執行出現異常的時候進行增強,獲得異常信息。 18 5、最終通知【after-returning】無論方法是否出現異常,最終通知中代碼總是會執行的。 19 --> 20 <aop:before method="recordIP" pointcut-ref="updatePointcut"/> 21 </aop:aspect> 22 </aop:config>
3、同理,只要你訪問調用了service層中刪除操作時就會觸發切面類上的方法,我這里是當用戶進行刪除操作,則會記錄執行刪除操作的用戶的IP地址並打印在日志中。
4、效果如圖:
[好了,哥們兒到站了,醒醒吧,是不是沒什么技術含量,把你都看醉了,哈哈哈~~~后期會給各位奉上hadoop相關的文章,因為一直在學習的路上,天氣甚好在首都向各位問好!]