java面向切面編程總結-面向切面的本質


面向切面的本質:定義切面類並將切面類的功能織入到目標類中;

實現方式:將切面應用到目標對象從而創建一個新的代理對象的過程。替換;

 

使用注解@Aspect來定義一個切面,在切面中定義切入點(@Pointcut),通知類型(@Before, @AfterReturning,@After,@AfterThrowing,@Around). 

https://www.cnblogs.com/oumyye/p/4480196.html

 

現將圖6-6中涉及到的一些概念解釋如下。

切面(Aspect):

其實就是共有功能的實現。如日志切面、權限切面、事務切面等。在實際應用中通常是一個存放共有功能實現的普通Java類,之所以能被AOP容器識別成切面,是在配置中指定的。

切面:織入類

@Aspect

public class MyAspect {}

 

通知(Advice):

是切面的具體實現。以目標方法為參照點,根據放置的地方不同,可分為前置通知(Before)、后置通知(AfterReturning)、異常通知(AfterThrowing)、最終通知(After)與環繞通知(Around)5種。在實際應用中通常是切面類中的一個方法,具體屬於哪類通知,同樣是在配置中指定的。

通知:織入類的事件;

@Aspect

@Component

public class LogInterceptor {

    @Pointcut("execution(public * com.oumyye.service..*.add(..))")

    public void myMethod(){};

    

    /*@Before("execution(public void com.oumyye.dao.impl.UserDAOImpl.save(com.oumyye.model.User))")*/

    @Before("myMethod()")

    public void before() {

        System.out.println("method staet");

    } 

    @After("myMethod()")

    public void after() {

        System.out.println("method after");

    } 

    @AfterReturning("execution(public * com.oumyye.dao..*.*(..))")

    public void AfterReturning() {

        System.out.println("method AfterReturning");

    } 

    @AfterThrowing("execution(public * com.oumyye.dao..*.*(..))")

    public void AfterThrowing() {

        System.out.println("method AfterThrowing");

    } 

}

 

通知傳遞參數

在Spring AOP中,除了execution和bean指示符不能傳遞參數給通知方法,其他指示符都可以將匹配的方法相應參數或對象自動傳遞給通知方法。獲取到匹配的方法參數后通過”argNames”屬性指定參數名。如下,需要注意的是args(指示符)、argNames的參數名與before()方法中參數名 必須保持一致即param。

@Before(value="args(param)", argNames="param") //明確指定了    

public void before(int param) {    

    System.out.println("param:" + param);    

}  

 

連接點(Joinpoint):

就是程序在運行過程中能夠插入切面的地點。例如,方法調用、異常拋出或字段修改等,但Spring只支持方法級的連接點。

連接點:目標類+目標函數;用於切面類在運行時獲取目標對象+函數+參量上下文信息;

@Around("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("環繞通知前....");

        Object obj= (Object) joinPoint.proceed();

        System.out.println("環繞通知后....");

        return obj;

    }

 

切入點(Pointcut):

用於定義通知應該切入到哪些連接點上。不同的通知通常需要切入到不同的連接點上,這種精准的匹配是由切入點的正則表達式來定義的。

切入點:在哪里(什么樣函數)織入;用於在切面中注解織入到哪些范圍的哪些函數上;

定義過濾切入點函數時,直接把execution以定義匹配表達式作為值傳遞給通知類型的如下:

@After(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")

  public void after(){

      System.out.println("最終通知....");

  } 

采用與ApectJ中使用pointcut關鍵字類似的方式定義切入點表達式如下,使用@Pointcut注解:

@Pointcut("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")

private void myPointcut(){}

@After(value="myPointcut()")

public void afterDemo(){

    System.out.println("最終通知....");

切入點指示符

為了方法通知應用到相應過濾的目標方法上,SpringAOP提供了匹配表達式,這些表達式也叫切入點指示符,在前面的案例中,它們已多次出現。

通配符

在定義匹配表達式時,通配符幾乎隨處可見,如*、.. 、+ ,它們的含義如下:

  • .. :匹配方法定義中的任意數量的參數,此外還匹配類定義中的任意數量包
    //任意返回值,任意名稱,任意參數的公共方法
  • execution(public * *(..))
  • //匹配com.zejian.dao包及其子包中所有類中的所有方法
  • within(com.zejian.dao..*) 
  • + :匹配給定類的任意子類
    //DaoUserwithin(com.zejian.dao.DaoUser+) 
  • * :匹配任意數量的字符
    匹配包及其子包中所有類的所有方法
  • within(com.zejian.service..*)
  • //匹配以set開頭,參數為int類型,任意返回值的方法
  • execution(* set*(int)) 

 

execution 用於匹配方法執行的連接點;

within 用於匹配指定類型內的方法執行;

 

目標對象(Target):

就是那些即將切入切面的對象,也就是那些被通知的對象。這些對象中已經只剩下干干凈凈的核心業務邏輯代碼了,所有的共有功能代碼等待AOP容器的切入。

目標對象:目標類

<!-- 定義目標對象 -->

    <bean id="userDaos" class="com.zejian.spring.springAop.dao.daoimp.UserDaoImp" />

 

代理對象(Proxy):

將通知應用到目標對象之后被動態創建的對象。可以簡單地理解為,代理對象的功能等於目標對象的核心業務邏輯功能加上共有功能。代理對象對於使用者而言是透明的,是程序運行過程中的產物。

代理對象:目標類織入切面功能后的中間層(類)

 

織入(Weaving):

將切面應用到目標對象從而創建一個新的代理對象的過程。這個過程可以發生在編譯期、類裝載期及運行期,當然不同的發生點有着不同的前提條件。譬如發生在編譯期的話,就要求有一個支持這種AOP實現的特殊編譯器;發生在類裝載期,就要求有一個支持AOP實現的特殊類裝載器;只有發生在運行期,則可直接通過Java語言的反射機制與動態代理機制來動態實現。

織入:織入的實現方式;

 

https://blog.csdn.net/liujiahan629629/article/details/18864211

 

 

基於XML的開發

前面分析完基於注解支持的開發是日常應用中最常見的,即使如此我們還是有必要了解一下基於xml形式的Spring AOP開發,這里會以一個案例的形式對xml的開發形式進行簡要分析,定義一個切面類

copycode.gif

/**

 * Created by zejian on 2017/2/20.*/

public class MyAspectXML {

 

    public void before(){

        System.out.println("MyAspectXML====前置通知");

    }

 

    public void afterReturn(Object returnVal){

        System.out.println("后置通知-->返回值:"+returnVal);

    }

 

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("MyAspectXML=====環繞通知前");

        Object object= joinPoint.proceed();

        System.out.println("MyAspectXML=====環繞通知后");

        return object;

    }

 

    public void afterThrowing(Throwable throwable){

        System.out.println("MyAspectXML======異常通知:"+ throwable.getMessage());

    }

 

    public void after(){

        System.out.println("MyAspectXML=====最終通知..來了");

    }

copycode.gif

通過配置文件的方式聲明如下(spring-aspectj-xml.xml):

copycode.gif

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

 

    <!--<context:component-scan base-package=""-->

 

    <!-- 定義目標對象 -->

    <bean name="productDao" class="com.zejian.spring.springAop.dao.daoimp.ProductDaoImpl" />

 

    <!-- 定義切面 -->

    <bean name="myAspectXML" class="com.zejian.spring.springAop.AspectJ.MyAspectXML" />

    <!-- 配置AOP 切面 -->

    <aop:config>

        <!-- 定義切點函數 -->

        <aop:pointcut id="pointcut" expression="execution(* com.zejian.spring.springAop.dao.ProductDao.add(..))" />

 

        <!-- 定義其他切點函數 -->

        <aop:pointcut id="delPointcut" expression="execution(* com.zejian.spring.springAop.dao.ProductDao.delete(..))" />

 

        <!-- 定義通知 order 定義優先級,值越小優先級越大-->

        <aop:aspect ref="myAspectXML" order="0">

            <!-- 定義通知

            method 指定通知方法名,必須與MyAspectXML中的相同

            pointcut 指定切點函數

            -->

            <aop:before method="before" pointcut-ref="pointcut" />

 

            <!-- 后置通知  returning="returnVal" 定義返回值 必須與類中聲明的名稱一樣-->

            <aop:after-returning method="afterReturn" pointcut-ref="pointcut"  returning="returnVal" />

 

            <!-- 環繞通知 -->

            <aop:around method="around" pointcut-ref="pointcut"  />

 

            <!--異常通知 throwing="throwable" 指定異常通知錯誤信息變量,必須與類中聲明的名稱一樣-->

            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="throwable"/>

 

            <!--

                 method : 通知的方法(最終通知)

                 pointcut-ref : 通知應用到的切點方法

                -->

            <aop:after method="after" pointcut-ref="pointcut"/>

        </aop:aspect>

    </aop:config>

beans 

copycode.gif

聲明方式和定義方式在代碼中已很清晰了,了解一下即可,在實際開發中,會更傾向與使用注解的方式開發

 

 

https://www.cnblogs.com/junzi2099/p/8274813.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM