詳解Spring Aop實(shí)現(xiàn)日志收集和重復(fù)屬性賦值
Spring Aop實(shí)現(xiàn)日志收集和重復(fù)屬性賦值
簡介
? AOP(Aspect-Oriented Programming),即面向切面編程,用人話說就是把公共的邏輯抽出來,讓開發(fā)者可以更專注于業(yè)務(wù)邏輯開發(fā)。
? 和IOC一樣,AOP也指的是一種思想。AOP思想是OOP(Object-Oriented Programming)的補(bǔ)充。OOP是面向類和對象的,但是AOP則是面向不同切面的。一個切面可以橫跨多個類和對象去操作,極大的豐富了開發(fā)者的使用方式,提高了開發(fā)效率。
譬如,一個訂單的創(chuàng)建,可能需要以下步驟:
- 權(quán)限校驗(yàn)
- 事務(wù)管理
- 創(chuàng)建訂單
- 日志打印
如果使用AOP思想,我們就可以把這四步當(dāng)成四個“切面”,讓業(yè)務(wù)人員專注開發(fā)第三個切面,其他三個切面則是基礎(chǔ)的通用邏輯,統(tǒng)一交給AOP封裝和管理。
Spring AOP有如下概念:
| 術(shù)語 | 翻譯 | 釋義 |
|---|---|---|
| Aspect | 切面 | 切面由切入點(diǎn)和通知組成,它既包含了橫切邏輯的定義,也包括了切入點(diǎn)的定義。切面是一個橫切關(guān)注點(diǎn)的模塊化,一個切面能夠包含同一個類型的不同增強(qiáng)方法,比如說事務(wù)處理和日志處理可以理解為兩個切面。 |
| PointCut | 切入點(diǎn) | 切入點(diǎn)是對連接點(diǎn)進(jìn)行攔截的條件定義,決定通知應(yīng)該作用于截哪些方法。(充當(dāng)where角色,即在哪里做) |
| Advice | 通知 | 通知定義了通過切入點(diǎn)攔截后,應(yīng)該在連接點(diǎn)做什么,是切面的具體行為。(充當(dāng)what角色,即做什么) |
| Target | 目標(biāo)對象 | 目標(biāo)對象指將要被增強(qiáng)的對象,即包含主業(yè)務(wù)邏輯的類對象。或者說是被一個或者多個切面所通知的對象。 |
| JoinPoint | 連接點(diǎn) | 連接點(diǎn)是程序在運(yùn)行時的執(zhí)行點(diǎn),這個點(diǎn)可以是正在執(zhí)行的方法,或者是正在拋出的異常。因?yàn)镾pring只支持方法類型的連接點(diǎn),所以在Spring中連接點(diǎn)就是運(yùn)行時刻被攔截到的方法。連接點(diǎn)由兩個信息確定:+ 方法(表示程序執(zhí)行點(diǎn),即在哪個目標(biāo)方法)+ 相對點(diǎn)(表示方位,即目標(biāo)方法的什么位置,比如調(diào)用前,后等) |
| Weaving | 織入 | 織入是將切面和業(yè)務(wù)邏輯對象連接起來, 并創(chuàng)建通知代理的過程。織入可以在編譯時,類加載時和運(yùn)行時完成。在編譯時進(jìn)行織入就是靜態(tài)代理,而在運(yùn)行時進(jìn)行織入則是動態(tài)代理。 |
對于通知類型來說:
| Before Advice | 連接點(diǎn)執(zhí)行前執(zhí)行的邏輯 |
|---|---|
| After returning advice | 連接點(diǎn)正常執(zhí)行(未拋出異常)后執(zhí)行的邏輯 |
| After throwing advice | 連接點(diǎn)拋出異常后執(zhí)行的邏輯 |
| After finally advice | 無論連接點(diǎn)是正常執(zhí)行還是拋出異常,在連接點(diǎn)執(zhí)行完畢后執(zhí)行的邏輯 |
| Around advice | 該通知可以非常靈活的在方法調(diào)用前后執(zhí)行特定的邏輯 |
代碼實(shí)現(xiàn)
1、創(chuàng)建注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}2、切面類
@Aspect
@Slf4j
@Component
public class LogAspect {
/**
* 切入點(diǎn)
*/
@Pointcut("execution(* com.zh.cn.*.*.*(..)) && @annotation(com.zh.cn.annotation.Log)")
public void LogAspect(){
}
@Before("LogAspect()")
public void before(JoinPoint joinPoint){
//收集日志系統(tǒng)
log.info("日志收集---前置通知");
//獲取日志收集中的實(shí)體類
log.info("參數(shù):{}",joinPoint);
//獲取basePojo實(shí)體類
Object[] args = joinPoint.getArgs();
Object entity = args[0];
try {
Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", Date.class);
Method setUpdateName = entity.getClass().getDeclaredMethod("setUpdateName", String.class);
//通過反射為對象賦值
setUpdateTime.invoke(entity,new Date());
setUpdateName.invoke(entity,"zh");
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
//收集日志
//~~~~
log.info("日志收集---后置通知");
}
}3、controller層
/**
* @Description:
* @author:<a href="2358853434@qq.com"></a> zh
* @Create : 2024/10/5
**/
@RestController
@RequestMapping("/order/v1")
public class OrderController {
@Resource
private OrderService orderService;
@GetMapping("/update")
public Result update() {
Order order = new Order();
order.setId(1292071939041697792L);
order.setName("測試商品");
order.setNum(128L);
return orderService.update(order);
}
@GetMapping("/insert")
public Result insert(){
return Result.success();
}
}4、service層
@Service
@Slf4j
public class OrderServiceimpl implements OrderService {
@Resource
RedisTemplate<String,String> redisTemplate;
@Resource
RedisDistributedLock redisDistributedLock;
/**
* 更新訂單接口
* @param order
* @return
*/
@Log
public Result update(Order order) {
log.info("update開始,訂單號:{}",order.getId()+"order:"+order);
//加鎖成功
while(redisDistributedLock.tryLock("order:"+order.getId()+":"+Thread.currentThread().getId(), "requestId", 10)) {
//執(zhí)行訂單減減
log.info("加鎖成功"+Thread.currentThread().getId());
redisTemplate.opsForValue().set("order:"+order.getId(), order.toString());
break;
}
if (redisDistributedLock.unlock("order:"+order.getId()+":"+Thread.currentThread().getId(),"requestId")) {
log.info("update結(jié)束,訂單號:{}",order.getId());
return Result.success();
}
return Result.error("下單失敗");
}
}5、測試 測試用例
由于項目中加了spring-security的相關(guān)依賴,需要配置Authorization,不需要的友友請自行刪除
GET http://localhost:19002/order/v1/update Authorization: Basic cm9vdDpyb290
結(jié)果

到此這篇關(guān)于Spring Aop實(shí)現(xiàn)日志收集和重復(fù)屬性賦值的文章就介紹到這了,更多相關(guān)Mysql全文檢索內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談mysql數(shù)據(jù)庫中的換行符與textarea中的換行符
下面小編就為大家?guī)硪黄獪\談mysql數(shù)據(jù)庫中的換行符與textarea中的換行符。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01
詳解如何用SQL取出字段內(nèi)是json的數(shù)據(jù)
數(shù)據(jù)庫中會遇到字段里面存的JSON結(jié)果的數(shù)據(jù),那么如果我們想直接取到JSON里的值該怎么辦呢?其實(shí)SQL自帶的函數(shù)就可解決本文就詳細(xì)的給大家介紹了如何用SQL取出字段內(nèi)是json的數(shù)據(jù),需要的朋友可以參考下2023-10-10
Mysql中日期和時間函數(shù)應(yīng)用不用求人
Mysql中日期和時間函數(shù)應(yīng)用不用求人,學(xué)習(xí)mysql的朋友可以參考下。2010-11-11
解決mysql登錄錯誤:''Access denied for user ''root''@''localhost''
這篇文章主要介紹了mysql登錄錯誤:'Access denied for user 'root'@'localhost',本文給出了操作過程及注意事項,需要的朋友可以參考下2019-11-11

