spring之AOP(面向切面編程)

1、簡介java

    何爲AOP,通俗的將就是給某些方法執行以前、執行以後等動做發生的時候執行某些操做,在執行這些操做的時候能夠獲取執行方法的相關信息,簡化程序開發中老是重複的東西,好比方法入參出參的日誌打印,用戶訪問權限校驗,事務控制等。spring

2、術語json

    通知(advice):切面的工做被稱爲通知。通俗點:何時怎麼幹啥事。編輯器

        1.前置通知(before):在目標方法被調用以前調用通知功能。代理

        2.後置通知(after):在目標方法完成以後調用通知,此事不會關心方法的輸出是什麼。日誌

        3.返回通知(after-returning):在目標方法成功執行以後調用通知。code

        4.異常通知(after-throwing):在目標方法跑出異常後調用通知。對象

        5.環繞通知(around):通知包裹了被通知的方法,在被通知的方法調用以前和調用以後執行自定義的行爲。生命週期

    鏈接點(joinpoint):使用通知的地方。事務

    切點(pointcut):匹配通知所要織入的一個或多個鏈接點。

    切面(aspect):通知和切點的結合定義切面的所有內容,它是什麼,在什麼時候何處完成其功能。

    引入(introduction):能夠向現有的類添加新方法和屬性。

    織入(weaving):把切面應用到目標對象並建立新的代理對象的過程。切面在制定的鏈接點被織入到目標對象中,在目標對象的生命週期裏有多個點能夠織入:

        1.編譯期:切面在目標類編譯時織入,這種方式須要特殊的編譯器,AspectJ的織入編輯器就是以這種方式織入切面的。

        2.類加載期:切面在目標類加載到JVM時織入,這種方式須要特殊的類加載器(ClassLoader),它能夠在目標類被引入應用以前加強該目標類的字節碼。

        3.運行期:切面在應用運行的某個時刻被織入,通常狀況下,在織入切面時,AOP容器會爲目標對象動態的建立一個代理對象,SpringAOP就是以這種方式織入切面的。

 

3、spring對AOP的支持

    spring提供了4種類型的AOP支持:

        1.基於代理的經典SpringAOP

        2.純POJO切面

        3.@AspectJ註解驅動的切面

        4.注入式AspectJ切面

    前三種是springAOP實現的變體,SpringAOP構建在動態代理的基礎之上,所以,spring對AOP的支持侷限於方法攔截。

4、spring只支持方法界別的鏈接點

    由於spring是基於動態代理,因此孩子恩可以支持方法級別的aop。AspectJ和JBoss,除了方法切點,還提供了字段和構造器接入點。spring缺乏字段鏈接點的支持,沒法讓咱們建立細粒度的通知,例如攔截對象字段的修改,並且他不支持構造器鏈接點,咱們就沒法再bean建立時應用通知。

5、切點表達式

    execution(* sundsystem.CompactDisc.playTrack(int))

    第一個* 返回任意類型

    sundsystem.CompactDisc 方法所屬的類型

    playTrack 方法

    int 接受int類型的參數

6、demo

    註解:

package com.pz.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
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.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

@Aspect
@Component
public class LogAspect {

	private static Logger logger = LoggerFactory.getLogger(LogAspect.class);
	
	@Pointcut("execution(public * com.pz.service..*.*(..))")
	public void logPoint(){}
	
	@Before("logPoint()")
	public void logBefor(JoinPoint joinPoint){
		String method = joinPoint.getSignature().getName();
		Object [] args = joinPoint.getArgs();
		String param = JSON.toJSONString(args);
		logger.info("[前置通知][{}] param:{}", method, param);
	}
	
	@After("logPoint()")
	public void logAfter(JoinPoint joinPoint){
		String method = joinPoint.getSignature().getName();
		Object [] args = joinPoint.getArgs();
		String param = JSON.toJSONString(args);
		logger.info("[後置通知][{}] result:{}", method, param);
	}
	
	@AfterReturning(pointcut="logPoint()", returning="result")
	public void logAfterReturning(JoinPoint joinPoint, Object result){
		String method = joinPoint.getSignature().getName();
		String response = JSON.toJSONString(result);
		logger.info("[返回通知][{}] return:{}", method, response);
	}
	
	@AfterThrowing(pointcut="logPoint()", throwing="e")
	public void logAfterThrowing(JoinPoint joinPoint, Exception e){
		String method = joinPoint.getSignature().getName();
		logger.error("[異常通知][{}] exception:{}", method, e.getMessage());
	}
	
	@Around("logPoint()")
	public Object logArount(ProceedingJoinPoint pjp) throws Throwable{
		Object result = null;
		String param = JSON.toJSONString(pjp.getArgs());
		String method = pjp.getSignature().getName();
		try{
			logger.info("[環繞通知][{}] param:{}", method, param);
			result = pjp.proceed();
			logger.info("[環繞通知][{}] result:{}", method, JSON.toJSON(result));
		}catch(Exception e){
			logger.error("[環繞通知][{}] exception:{}", method, e.getMessage());
			 throw new RuntimeException(e);
		}
		logger.info("[環繞通知][{}] return:{}", method, JSON.toJSON(result));
		return result;
	}

}
相關文章
相關標籤/搜索