1. 程式人生 > >Spring 4.0 學習日記(8) ---AOP切面註解實現五種通知

Spring 4.0 學習日記(8) ---AOP切面註解實現五種通知

寫在前面 會有專門的一章來備註AOP切面各種的知識點
這裡我只寫通過註解實現的五種通知 其實我就是懶~~~略略略略略略

通知(Advice)型別

前置通知(Before advice):在某連線點(JoinPoint)之前執行的通知,但這個通知不能阻止連線點前的執行。ApplicationContext中在<aop:aspect>裡面使用<aop:before>元素進行宣告。例如,TestAspect中的doBefore方法。

後置通知(After advice):當某連線點退出的時候執行的通知(不論是正常返回還是異常退出)。ApplicationContext中在<aop:aspect>

裡面使用<aop:after>元素進行宣告。例如,ServiceAspect中的returnAfter方法,所以Teser中呼叫UserService.delete丟擲異常時,returnAfter方法仍然執行。

返回通知(After return advice):在某連線點正常完成後執行的通知,不包括丟擲異常的情況。ApplicationContext中在裡面使用元素進行宣告。

環繞通知(Around advice):包圍一個連線點的通知,類似Web中Servlet規範中的Filter的doFilter方法。可以在方法的呼叫前後完成自定義的行為,也可以選擇不執行。ApplicationContext中在<aop:aspect>

裡面使用<aop:around>元素進行宣告。例如,ServiceAspect中的around方法。

丟擲異常後通知(After throwing advice):在方法丟擲異常退出時執行的通知。ApplicationContext中在<aop:aspect>裡面使用<aop:after-throwing>元素進行宣告。例如,ServiceAspect中的returnThrow方法。

注1:可以將多個通知應用到一個目標物件上,即可以將多個切面織入到同一目標物件。
(我的例項就是多個通知注入到一個方法上 但是異常通知為啥不實現呢)

注2:以為我把所有的類寫到一個包下面了 所以掃描的時候就是那一個包

下面是例項

interface類

package com.wow.AopMessage;

public interface AopServiceInterface {

    public String addInfo(int i,int b,int j);
}

實現介面方法的類 這裡的方法帶了引數是為了測試around通知的時候是否打印出了引數
getArgs():獲取連線點方法執行時的入參列表

package com.wow.AopMessage;

public class AopServiceImpl implements AopServiceInterface{

    @Override
    public String addInfo(int a,int b,int c) {
        System.out.println("--------------------");
        System.out.println("實現類方法addInfo已經執行");
        System.out.println("--------------------");
        return this.getClass().getName();
    }

}

切面類

package com.wow.AopMessage;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;

@Aspect
public class AopMessageInfo {

    /****
     * 宣告該方法是一個前置通知:在目標方法開始之前執行 
     * 
     * JoinPoint 是連線點,代表一個方法,客戶端呼叫哪個方法,哪個方法就是連線點 通過該引數,可以獲取到連線點的一些資訊
     * 
     * "execution(* com.wow.AopMessage.*.*(..))"
     * 
     * 第一個* 任意修飾符和任意返回值 
     * 第二個* 該包下所有的類 
     * 第三個* 所有方法 
     * (..) 所有引數
     */
    @Before("execution(* com.wow.AopMessage.*.*(..))")
    public void Before(JoinPoint jPonit) {
        System.out.println("--------------------");
        // 獲取目標類
        System.out.println("targetClass:" + jPonit.getTarget());
        // 獲取連線點的引數
        System.out.println("args:" + jPonit.getArgs());
        // 獲取連線點的名稱
        System.out.println("methodName:" + jPonit.getSignature().getName());
        System.out.println("前置通知已完成----開啟事務");
        System.out.println("--------------------");

    }

    /**
     * 返回通知:在目標方法正常結束執行後的通知 
     * 返回通知是可以訪問到目標方法的返回值
     * 在後置通知後執行
     */

    @AfterReturning(value = "execution(* com.wow.AopMessage.*.*(..))", returning = "result")
    public void afterRunningMethod(JoinPoint jPonit, Object result) {
        System.out.println("--------------------");
        System.out.println("methodName:" + jPonit.getSignature().getName());
        System.out.println("The method " + jPonit.getSignature().getName()
                + " ends with the Result " + result);
        System.out.println("返回通知已完成----獲取目標方法返回值"+result);
        System.out.println("--------------------");

    }

    /**
     * 
     * 後置通知:在目標方法之後(無論是否發生異常),執行的通知,
     * 在後置通知中還不能訪問目標方法執行的結果。執行結果須在返回通知中訪問。
     *  
     * JoinPoint
     */

    @After("execution(* com.wow.AopMessage.*.*(..))")
    public void After(JoinPoint jPonit) {
        System.out.println("--------------------");
        System.out.println("methodName:" + jPonit.getSignature().getName());
        System.out.println("後置通知已完成----提交事務");
        System.out.println("--------------------");

    }

     /**
     * 環繞通知
     *    需要攜帶ProceedingJoinPoint型別的引數
     * 類似於動態代理的全過程:ProceedingJoinPoint型別引數可以決定是否執行目標方法
     * 環繞通知必須有返回值,返回值就是目標方法的返回值
     * 
     */

    /**
     * org.aspectj.lang.JoinPoint介面表示目標類連線點物件.
     * org.aspectj.lang.ProceedingJoinPoint表示連線點物件,該類是JoinPoint的子介面.
     * 
     * JoinPoint 
     * java.lang.Object[] getArgs():獲取連線點方法執行時的入參列表;
     * getSignature() :獲取連線點的方法簽名物件; 
     * java.lang.Object getTarget() :獲取連線點所在的目標物件; 
     * java.lang.Object getThis() :獲取代理物件本身; 
     * 
     * ProceedingJoinPoint 
     * roceedingJoinPoint繼承JoinPoint子介面,它新增了兩個用於執行連線點方法的方法: 
     * java.lang.Object proceed() throws java.lang.Throwable:通過反射執行目標物件的連線點處的方法; 
     * java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:
     * 通過反射執行目標物件連線點處的方法,不過使用新的入參替換原來的入參。
     */

    @Around("execution(* com.wow.AopMessage.*.*(..))") 
    public Object around(ProceedingJoinPoint jPonit){  
        Object result = null;  
        String methodName = jPonit.getSignature().getName();  
        Object args = Arrays.asList(jPonit.getArgs());  
        //執行目標方法  
        try {  
            //前置通知  
            System.out.println("--------------------");
            System.out.println("Arround:The method "+methodName +" begins with "+ args);
            System.out.println("--------------------");
            result = jPonit.proceed();  
            //後置通知  
            System.out.println("--------------------");
            System.out.println("Arround:The method "+ methodName+" ends");
            System.out.println("--------------------");
        } catch (Throwable e) {  
            e.printStackTrace();  
            //異常通知  
            System.out.println("Arround:The method "+ methodName+"occurs exception:"+e);  
            //throw new RuntimeException(e);  
            //不丟擲異常的話,異常就被上面抓住,執行下去,返回result,result值為null,轉換為int  
        }  
        //返回通知  
        System.out.println("--------------------");
        System.out.println("Arround:The method "+ methodName+" ends with the Result "+ result);  
        System.out.println("--------------------");
        //return 方法名;  
        return result;  
    }  


    /**
     * 在目標方法出現異常時會執行的程式碼,
     * 可以訪問到異常物件,且可以指定在出現特定異常時在執行通知程式碼
     * 如下面Exception ex,方法引數Exception改為其它異常可以指定出現指定異常時執行
     * 這裡沒有報異常  以後有時間再說吧  
     */
    @AfterThrowing(value = "execution(* com.wow.AopMessage.*.*(..))", throwing = "ex")
    public void afterThrowingMethod(JoinPoint jPonit, Exception ex) {
        System.out.println("methodName:" + jPonit.getSignature().getName());
        System.out.println("The method " + jPonit.getSignature().getName()
                + "occurs exception:" + ex);
    }
}

測試類

package com.wow.AopMessage;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {

    public static void main(String[] args) {
        ApplicationContext App = new ClassPathXmlApplicationContext("beans.xml");
        AopServiceImpl AopSer = (AopServiceImpl) App.getBean("AopService");
        AopSer.addInfo(1,2,3);
    }
}

xml配置檔案 這裡為了實現的aop:aspectj 表頭檔案有修改 主要就是AOP和Context

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <!-- 啟用元件掃描功能,在包com.wow.AopMessage及其子包下面自動掃描通過註解配置的元件 -->        
   <context:component-scan base-package="com.wow.AopMessage"/>      

    <bean id = "AopService" class = "com.wow.AopMessage.AopServiceImpl"></bean>
    <bean id = "AopMessage" class = "com.wow.AopMessage.AopMessageInfo"></bean>

    <!-- proxy-target-class屬性值決定是基於介面的還是基於類的代理被建立。
    如果proxy-target-class 屬性值被設定為true,那麼基於類的代理將起作用(這時需要cglib庫)。
    如果proxy-target-class屬值被設定為false或者這個屬性被省略,那麼標準的JDK 基於介面的代理將起作用 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <!-- 當採取預設忽略這個屬性的時候發生以下錯誤 為啥我也不知道 等我複習到XML配置或者cglib代理的時候就知道了 動態代理除了JDK的另外一種代理
    Exception in thread "main" java.lang.ClassCastException: 
    com.sun.proxy.$Proxy7 cannot be cast to com.wow.AopMessage.AopServiceImpl
    <aop:aspectj-autoproxy/> -->
</beans>  

列印結果 其實看下每個通知的出現順序

八月 01, 2017 11:24:37 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
資訊: Refreshing org[email protected]3b85c6ac: startup date [Tue Aug 01 23:24:37 CST 2017]; root of context hierarchy
八月 01, 2017 11:24:37 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
資訊: Loading XML bean definitions from class path resource [beans.xml]
--------------------
Arround:The method addInfo begins with [1, 2, 3]
--------------------
--------------------
targetClass:[email protected]
args:[Ljava.lang.Object;@14fb3758
methodName:addInfo
前置通知已完成----開啟事務
--------------------
--------------------
實現類方法addInfo已經執行
--------------------
--------------------
Arround:The method addInfo ends
--------------------
--------------------
Arround:The method addInfo ends with the Result com.wow.AopMessage.AopServiceImpl
--------------------
--------------------
methodName:addInfo
後置通知已完成----提交事務
--------------------
--------------------
methodName:addInfo
The method addInfo ends with the Result com.wow.AopMessage.AopServiceImpl
返回通知已完成----獲取目標方法返回值com.wow.AopMessage.AopServiceImpl
--------------------

恩 以上 很簡單 沒啥難的

相關推薦

Spring 4.0 學習日記8 ---AOP切面註解實現通知

寫在前面 會有專門的一章來備註AOP切面各種的知識點 這裡我只寫通過註解實現的五種通知 其實我就是懶~~~略略略略略略 通知(Advice)型別 前置通知(Before advice):在某連線點(JoinPoint)之前執行的通知,但這個通知不能

Spring 4.0 學習日記9 ---XML配置實現AOP切面

Spring建立代理的規則 1.預設使用Java動態代理來建立AOP代理 2.當需要代理的類不是代理介面的時候,Spring會切換為使用CGLIB代理,也可強制使用CGLIB 其實Xml配置更簡單 直接看程式碼就懂了 介面類 package co

Spring Boot2.0學習筆記

target uil pom true framework build 項目 組件 文件 1、Spring Boot項目啟動方式 (1)主程序啟動 @SpringBootApplication public class HelloApplication { pu

Spring學習日記AOP的深入操作

上次的AOP操作簡單,但對初學者而言,刪繁就簡地體現了aop的設計思想。但有些過於簡化了,本次將把引數帶入到aop的操作中。 一、前置通知中含引數 1、修改切面處理類:改寫serviceBefore(),使其含有引數 public void serviceBefor

jeesite 4.0 學習筆記

本人小白一個,公司要開發一個下單系統,專案週期比較短,兩週時間。重新開發已經是不可能的了。部門的工程師建議用jeesite快速開發框架。去官網看了一下,http://www.jeesite.com/,感覺還ok。框架已經更新到4.0版本了,本以為很簡單,沒想到一用才發現很多問

Spring 學習筆記AOP註解方式與零配置方式

術語先來一發 目標物件(Target) 代理物件(Proxy) 連線點(Joinpoint) 切入點(Pointcut) 通知(增強)(Advice) 切面(Aspect、Advisor) 織入、切入(weaving) 1. 建立目標物件和代理物

spring boot 學習筆記 8MyBatis 註解

註解版 註解版的使用方式和 XML 版本相同,只有在構建 SQL 方面有所區別,所以本課重點介紹兩者之間的差異部分。 相關配置 註解版在 application.properties 只需要指明實體類的包路徑即可,其他保持不變: mybatis.type-aliases-packag

Spring Boot學習總結8——SpringBoot Common application propertiesapplication.properties詳解

# =================================================================== # COMMON SPRING BOOT PROPERTIES # # This sample file is provided as a guideline. Do N

Spring學習日記搭建MVC基本開發環境

一、準備工作 1、新建web project 2、新增spring開發支援       此時會自動配置上web包,其中包含了springMVC支援。也就是說可以直接在專案中使用Spring MVC了 3、定義相關配置 (1)Spring MVC的所有配置都要在a

Spring框架學習筆記8——spring boot+mybatis plus+mysql專案環境搭建

之前寫的那篇Spring框架學習筆記(5)——Spring Boot建立與使用,發現有多小細節沒有提及,,正好現在又學習了mybatis plus這款框架,打算重新整理一遍,並將細節說清楚 1.通過IDEA建立spring boot 2.專案相關配置 只需要修改第一個和第二個,下面的其他選項會自動改變

Linux學習日記

linux 命令 對於Linux新手來說,要想入門必先打好基礎,而Linux的命令就是這基礎中的重中之重。 首先學習了幫助命令Man的使用,Man可以查看命令的作用以及可用參數。並且如何去看幫助文檔中的內容NAME 使用命令的名稱 SYNOPSIS 命令參數的大致使用方法EXAMP

Swift學習筆記8:枚舉

check oss 函數 not 條形碼 blog 出現 現在 pan 目錄: 基本語法 關聯值 原始值 枚舉為一組相關的值定義了一個共同的類型。 ?可以給枚舉成員指定原始值類型:字符串,字符,整型值或浮點數等 ?枚舉成員可以指定任意類型的關聯值存儲

struts2學習筆記8-------struts2的ajax支持

net fcm utf-8 asc uri () nal extends keyword struts2支持一種stream類型的Result,這樣的類型的Result能夠直接向client瀏覽器響應二進制,文本等。 我們能夠再

thphp5.0學習筆記

mic tel 序號 app clas world char p s 庫類 1.目錄結構: 其中thinkphp子目錄是框架核心目錄 thinkphp結構: 2.入口文件 默認自帶的入口文件位於public/index.php 應用目錄為application,其結構

thinkphp5.0學習筆記API後臺處理與命名空間

mac code 輸入 -1 pub 基礎 select() color 第一個 命名空間 先來看命名空間吧; 命名空間是學習TP的基礎, <?php namespace app\lian\c1; class yi{ public $obj = "這是第一個

thinkphp5.0學習筆記獲取信息,變量,綁定參數

名稱 自動識別 參數順序 query images 報錯 oca nds arc 1.構造函數: 控制器類必須繼承了\think\Controller類,才能使用: 方法_initialize 代碼: <?php namespace app\lian\control

.net core 2.0學習筆記:遷移.net framework 工程到.net core

編譯 its evel hashtable ref 學習筆記 inline null 創建 在遷移.net core的過程中,第一步就是要把.net framework 工程的目標框架改為.net core2.0,但是官網卻沒有提供轉換工具,需要我們自己動手完成了

.net core 2.0學習筆記:Remoting核心類庫RealProxy遷移

ride dispatch 包含 void reflect 既然 splay creat (六) 在學習.net core的過程中,我們已經明確被告知,Remoting將不會被支持。官方的解釋是,.net framework 類型包含了太多的Runtime的內容,是

JXLS 2.4.0系列教程——循環導出一個鏈表的數據

教程 super 最簡 com arraylist port 至少 ron mod 請務必先看上一篇文章,本文在上一篇文章的代碼基礎上修改而成。 JXLS 2.4.0系列教程(一)——最簡單的模板導出 上一篇文章我們介紹了JXLS和模板導出最簡單的應用,現在我們要更進一

JXLS 2.4.0系列教程——多sheet是怎麽做到的

while director write 教程 == 模板 phy sheet ack 註:本文代碼在第一篇文章基礎上修改而成,請務必先閱讀第一篇文章。 http://www.cnblogs.com/foxlee1024/p/7616987.html 本文也不會過多的講解模