spring aop(一)

spring aop 是 spring 面向切面編程的實現,不影響原業務的基礎上,加入通用的功能,如所有業務功能都需要加入登錄功能,所有業務代碼加入輸入輸出日誌,加入參數校驗,加入統一的異常處理等,都可以用aop 實現。OOP 的編程的補償

在這裏插入圖片描述


1.概念:

1.目標對象(Target Object)::你寫的業務類,要增強的類,通常也是指被代理被通知的對象。
2.連接點(JointPoint):程序執行過程中明確的點,一般是方法調用。被攔截到的點,因爲Spring只支持方法類型的連接點,所以在Spring中連接點指的是被攔截的方法,實際上連接點還可以是字段或者構造器(自己的理解:目標方法的連接點 ,目標類的要被做操作的方法)
3.切面(Aspect): 通常是個類,裏面可以定義切入點通知
4.切入點(Pointcut): 再切面中定義的切點,就是通知上的連接點,再程序中主要體現爲書寫切入點表達式。

5.織入(weave): 切面應用到目標對象並導致代理對象創建過程
6.引入(introduction):再不修改代碼的前提下,引入可以再運行期爲類動態地添加一些方法或字段
7.AOP 代理(AOP Proxy):AOP 框架創建的對象,代理就是目標對象的加強。Spring 中的AOP 代理可以使JDK動態代理,也可以是CGLAB 代理,前者基於接口,後者基於子類。

8.通知(Advice): AOP 再特定的切入點上執行的增強處理,有before(前置),after(後置),afterReturning(最終),afterThrowing(異常),around(環繞)
(1)Before:在目標方法被調用之前做增強處理,@Before只需要指定切入點表達式即可

(2)AfterReturning:在目標方法正常完成後做增強,@AfterReturning除了指定切入點表達式後,還可以指定一個返回值形參名returning,代表目標方法的返回值

(3)AfterThrowing:主要用來處理程序中未處理的異常,@AfterThrowing除了指定切入點表達式後,還可以指定一個throwing的返回值形參名,可以通過該形參名

來訪問目標方法中所拋出的異常對象

(4)After:在目標方法完成之後做增強,無論目標方法時候成功完成。@After可以指定一個切入點表達式

(5)Around:環繞通知,在目標方法完成前後做增強處理,環繞通知是最重要的通知類型,像事務,日誌等都是環繞通知,注意編程中核心是一個ProceedingJoinPoint

9.橫切關注點::對哪些方法進行攔截,攔截後怎麼處理,這些關注點被稱爲橫切關注點


2.使用場景:

Authentication 權限
Caching 緩存
Context passing 內容傳遞
Error handling 錯誤處理
Lazy loading 懶加載
Debugging  調試
logging, tracing, profiling and monitoring 記錄跟蹤 優化 校準
Performance optimization 性能優化
Persistence  持久化
Resource pooling 資源池
Synchronization 同步
Transactions 事務



3.使用AOP的幾種方式:

1.經典的基於代理的AOP
2.@AspectJ註解驅動的切面
3.純POJO切面(純粹通過aop:fonfig標籤配置)
4.注入式AspectJ切面

4.具體使用方式(Springboot aop 實現)

引入aop 依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

不需要使用@EnableAspectJAutoProxy來啓用切面,因爲spring.aop.auto屬性是默認開啓的,也就是說引入aop 依賴默認添加了@EnableAspectJAutoProxy

當我們使用CGLIB 來實現aop 實現,需要配置spring.aop.proxy-target-class=true,不然默認使用的是標準java的實現。

實現代碼

@Aspect
@Component
public class AopAspectDemo {

    private Logger logger = Logger.getLogger(getClass().getName());

    ThreadLocal<Long> startTime = new ThreadLocal<Long>();

    @Pointcut("execution(public * com.study.project.api.*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        startTime.set(System.currentTimeMillis());
        // 接收到請求,記錄請求內容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 記錄下請求內容
        logger.info("URL : " + request.getRequestURL().toString());
        logger.info("HTTP_METHOD : " + request.getMethod());
        logger.info("IP : " + request.getRemoteAddr());
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));

    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 處理完請求,返回內容
        logger.info("RESPONSE : " + ret);
        logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
    }

}

aop切面中的同步問題:切面中通過doBefore 和 AfterReturning 兩個獨立的函數,計算運算請求處理時間,前置通知和返回後置通知處理一個變量,基本類型會有同步問題,所以要引入 ThrealLocal 對象。

由於通過aop實現,程序員得到了很好的解耦,但是也會帶來一些問題,比如:我們可能會對web層做了多個切面,校驗用戶,校驗信息等等,這時候就碰到處理順序問題。
所以我們用@Order(i) 註解來標識切面的優先級。
在切入點前的操作,按order的值由小到大執行
在切入點後的操作,按order的值由大到小執行

參考博客:aop 概念和方案
springboot aop 實現


要克服生活的焦慮和沮喪,得先學會做自己的主人,學會感恩,學會打磨生活,有問題留言,沒問題留下你的贊
博客聲明:
1.博客內容全是對工作學習的總結。
2.知識點都經過測試和推敲,如有疑問請留言,一定及時解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章