Spring學(xué)習(xí)手札(二)面向切面編程AOP

AOP理解

Aspect Oriented Program面向切面編程,通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。

但是,這種說法有些片面,因為在軟件工程中,AOP的價值體現(xiàn)的并不是代碼方面,更多的是為了項目的模塊化,而不僅僅是為了減少重復(fù)代碼。

AOP是一種編程思想,為的是讓模塊本身變得更加內(nèi)聚,讓開發(fā)者更多的關(guān)注到業(yè)務(wù)邏輯的開發(fā)。

在面向切面編程里,把功能分為核心業(yè)務(wù)功能和周邊業(yè)務(wù)功能:

核心業(yè)務(wù),比如登陸,日常增,刪數(shù)據(jù)

周邊功能,統(tǒng)計,日志,事務(wù)管理。在Spring的面向切面編程AOP思想里,即被定義為切面

在面向切面的思想里,核心業(yè)務(wù)功能和切面功能單獨開發(fā),然后把兩個整合在一起,就是AOP。

AOP實現(xiàn)原理

AOP底層將采用代理機制進(jìn)行實現(xiàn)

接口+實現(xiàn)類:spring采用jdk的動態(tài)代理Proxy

實現(xiàn)類:spring采用cglib字節(jié)碼增強

Spring默認(rèn)使用JDK動態(tài)代理,在需要代理類而不是接口的時候,Spring會自動切換為使用cglib代理,不過現(xiàn)在的項目都是面向接口開發(fā),所以JDK動態(tài)代理相對來說用的還是多一些。

Spring AOP引入了幾個概念

切面(Aspect),它是跨不同Java類層面的橫切性邏輯??梢酝ㄟ^XML文件中配置的普通類,也可以在類代碼中使用“@Aspect” 注解去聲明,在運行時,Spring會創(chuàng)建類似Advisor來代替它。其內(nèi)部包括切入和通知。通俗的講,是要告訴Spring什么時候,什么地方,做什么。

連接點(JoinPoint),程序運行過程中明確的點,一般是方法的調(diào)用。

通知(Advice),AOP在特定的切入點上知性的增強處理,告訴Spring什么時候,做什么。一般會講Advice模擬成一個攔截起,并且在JoinPoint上維護(hù)多個Advice,進(jìn)行層攔截。比如Http鑒權(quán)的實現(xiàn)。

切入點(PointCut),就是帶有通知的連接點。要切入的對象,可以是類,或方法。在Spring中,所有的方法都可以認(rèn)為是JoinPoint,都可以添加Advice,但是這并不是所有都是我們真正想要的,而PointCut提供了一組規(guī)則,來匹配JointPoint,給滿足規(guī)則的JointPoint添加Advice。其主要用來修飾JointPoint。

Advice的五種通知類型

前置通知(@Before):在目標(biāo)方法被調(diào)用之前調(diào)用通知功能

后置通知(@After):在目標(biāo)方法完成之后調(diào)用通知,此時不會關(guān)心方法的輸出

返回通知(@After-Returning):在目標(biāo)方法成功執(zhí)行之后調(diào)用通知

異常通知(@AfterThrowing):在目標(biāo)方法拋出異常后調(diào)用通知

環(huán)繞通知(@Around):通知包裹了被通知的方法,在被通知的方法調(diào)用之前和之后執(zhí)行自定義的行為

做個小demo

1. 在src下新建bean包,新建Operator類

package bean; 
import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.*; 
import org.springframework.stereotype.Component;

@Component
@Aspect public class Operator { 

// @Pointcut("execution(* service.UserService.add()") 
// public void service() { //
 }

 @Pointcut("execution(* service.UserService.add())") public void IService(){
    }

    @Before("IService()") public void doBefore(JoinPoint joinPoint) {
        System.out.println("  before Advice");
    }

    @After("IService()") public void doAfter(JoinPoint joinPoint) {
        System.out.println("  after Advice");
    }

    @AfterReturning(pointcut = "IService()", returning = "returnVal") public void afterReturn(JoinPoint joinPoint, Object returnVal) {
        System.out.println(" after Advice return " + returnVal);
    }

    @AfterThrowing(pointcut = "IService()", throwing = "errors") public void afterThrowing(JoinPoint joinPoint, Throwable errors) {
        System.out.println("afterThrowing Advice ..." + errors);
        System.out.println(" afterThrowing..");
    }

    @Around("IService()") public void doAround(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println(" around Advice  before"); try {
            proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println(" around Advice  before");
    }
}
  1. src下新建service包,新建UserService類
package service; 
import org.springframework.stereotype.Service;

@Service public class UserService { public void add() {
        System.out.println("UserService add.");
    } public boolean delete() {
        System.out.println("UserService delete .."); return true;
    } public void edit() {
        System.out.println("UserService edit ");
    }
}

3.配置XML文件,在src下新建applicationContext.xml

<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/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean name="userService" class="service.UserService"></bean>
    <bean name="operator" class="bean.Operator"></bean>

    <aop:config>
        <aop:aspect id="operatorAspect" ref="operator">
            <aop:pointcut id="servicePointCut" expression="execution(* service.UserService.add())"></aop:pointcut>
            <aop:before pointcut-ref="servicePointCut" method="doBefore"></aop:before>
            <aop:after pointcut-ref="servicePointCut" method="doAfter"></aop:after>
            <aop:around pointcut-ref="servicePointCut" method="doAround"></aop:around>
            <aop:after-returning pointcut-ref="servicePointCut" method="afterReturn" returning="returnVal"></aop:after-returning>
            <aop:after-throwing pointcut-ref="servicePointCut" method="afterThrowing" throwing="errors"></aop:after-throwing>
        </aop:aspect>
    </aop:config>
</beans>

4.測試AOP,在src下新建test.java

import bean.User; 
import org.junit.Test; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import service.UserService; 

public class test {
    @Test public void demo() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService", UserService.class);
        userService.add();
    }

}

5.運行結(jié)果


1538475300787.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容