SpringBoot項(xiàng)目使用aop案例詳解
前言
IOC和AOP是Spring中的兩個(gè)核心的概念,簡(jiǎn)單介紹一下我的理解:
IOC:控制反轉(zhuǎn),就是將以前由我們自己手動(dòng)創(chuàng)建對(duì)象的過(guò)程交給了Spring,Spring幫助我們生產(chǎn)對(duì)象、管理對(duì)象、管理對(duì)象和對(duì)象之間的依賴(lài)關(guān)系。降低了代碼的耦合度,方便我們后期對(duì)項(xiàng)目做維護(hù)。舉個(gè)通俗一點(diǎn)的例子:
正常情況下,我們?cè)诩?,餓了,自己做飯。
使用IOC情況下,我們?cè)诩?,餓了,打電話給商家,飯送過(guò)來(lái)。
IOC就相當(dāng)于商家,做飯就相當(dāng)于創(chuàng)建對(duì)象。
也就是說(shuō)正常情況下,當(dāng)一個(gè)類(lèi)需要調(diào)用其他類(lèi)的方法時(shí),我們手動(dòng)通過(guò)new、工廠或者其他方式創(chuàng)建對(duì)象。
使用IOC情況下,我們只需要注入對(duì)象即可。
AOP:面向切面(方便)編程,可以對(duì)某一類(lèi)對(duì)象進(jìn)行監(jiān)督和控制,在調(diào)用這類(lèi)對(duì)象方法的前后去調(diào)用指定的代碼,從而對(duì)一個(gè)方法進(jìn)行擴(kuò)展,從而達(dá)到增強(qiáng)模塊功能的效果。舉個(gè)通俗一點(diǎn)的例子:
正常情況下,直接吃飯。
使用AOP情況下,有個(gè)保姆關(guān)注著,吃飯前幫忙洗手,吃飯后幫忙收拾碗筷。
AOP就相當(dāng)于保姆,吃飯就相當(dāng)于帶調(diào)用具體的方法。
也就是說(shuō),當(dāng)我們想對(duì)方法進(jìn)行補(bǔ)充時(shí),并不去直接修改方法,而是通過(guò)AOP去補(bǔ)充。當(dāng)我們不想補(bǔ)充或者需要更換補(bǔ)充的時(shí)候,直接操作AOP即可。
1、Pointcut: 切點(diǎn),用于定義哪個(gè)方法會(huì)被攔截,例如 execution(* cn.springcamp.springaop.service..(…))
2、Advice: 攔截到方法后要執(zhí)行的動(dòng)作
3、Aspect: 切面,把Pointcut和Advice組合在一起形成一個(gè)切面
4、Join Point: 在執(zhí)行時(shí)Pointcut的一個(gè)實(shí)例
4、Weaver: 實(shí)現(xiàn)AOP的框架,例如 AspectJ 或 Spring AOP
一、SpringBoot項(xiàng)目引入AOP依賴(lài)
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>啟動(dòng)類(lèi)加上@EnableAspectJAutoProxy注解,可以省略。因?yàn)樵贏OP的默認(rèn)配置屬性中,spring.aop.auto屬性默認(rèn)是開(kāi)啟的。
也不需要再引入AspectJ依賴(lài)了。
二、普通方式
切面類(lèi)代碼:
package com.example.myblog.test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AOPTest {
//定義切入點(diǎn)
@Pointcut("execution(public * com.example.myblog.test.AOPTestClient.*(..))")
public void aspectTest(){}
//前置通知,切入點(diǎn)執(zhí)行之前執(zhí)行
@Before("aspectTest()")
public void doBefore(JoinPoint joinPoint){
System.out.println("前置通知");
}
//后置通知,切入點(diǎn)執(zhí)行之后執(zhí)行
@After("aspectTest()")
public void doAfter(JoinPoint joinPoint){
System.out.println("后置通知");
}
//最終通知,,切入點(diǎn)執(zhí)行之后執(zhí)行
@AfterReturning("aspectTest()")
public void doAfterReturning(JoinPoint joinPoint){
System.out.println("最終通知");
}
//異常通知,切入點(diǎn)拋出異常執(zhí)行
@AfterThrowing("aspectTest()")
public void deAfterThrowing(JoinPoint joinPoint){
System.out.println("異常通知");
}
//環(huán)繞通知,切入點(diǎn)執(zhí)行前、后執(zhí)行
@Around("aspectTest()")
public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("未執(zhí)行");
Object result = joinPoint.proceed();
System.out.println("已執(zhí)行");
//返回結(jié)果
return result;
}
}
切點(diǎn)類(lèi)代碼:
package com.example.myblog.test;
import org.springframework.stereotype.Component;
@Component
public class AOPTestClient {
public void test(){
System.out.println("正在測(cè)試AOP");
}
}測(cè)試類(lèi)代碼:
package com.example.myblog;
import com.example.myblog.test.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class MyblogApplicationTests {
@Autowired
private AOPTestClient aopTestClient;
@Test
public void testAOP(){
aopTestClient.test();
}
}測(cè)試結(jié)果:

三、注解方式
自定義注解代碼:
package com.example.myblog.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//表示次注解可以標(biāo)注在類(lèi)和方法上
@Target({ElementType.METHOD, ElementType.TYPE})
//運(yùn)行時(shí)生效
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
//定義一個(gè)變量,可以接受參數(shù)
String desc() default " ";
}切面類(lèi)代碼:
package com.example.myblog.test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AOPAnnotationTest {
//定義切入點(diǎn)
@Pointcut("@annotation(com.example.myblog.test.MyAnnotation)")
public void aspectTest(){}
//前置通知,切入點(diǎn)執(zhí)行之前執(zhí)行
@Before("aspectTest()")
public void doBefore(JoinPoint joinPoint){
System.out.println("前置通知");
}
//后置通知,切入點(diǎn)執(zhí)行之后執(zhí)行
@After("aspectTest()")
public void doAfter(JoinPoint joinPoint){
System.out.println("后置通知");
}
//最終通知,,切入點(diǎn)執(zhí)行之后執(zhí)行
@AfterReturning("aspectTest()")
public void doAfterReturning(JoinPoint joinPoint){
System.out.println("最終通知");
}
//異常通知,切入點(diǎn)拋出異常執(zhí)行
@AfterThrowing("aspectTest()")
public void deAfterThrowing(JoinPoint joinPoint){
System.out.println("異常通知");
}
//環(huán)繞通知,切入點(diǎn)執(zhí)行前、后執(zhí)行
@Around("aspectTest()")
public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("未執(zhí)行");
Object result = joinPoint.proceed();
System.out.println("已執(zhí)行");
//返回結(jié)果
return result;
}
}
切點(diǎn)類(lèi)代碼:
package com.example.myblog.test;
import org.springframework.stereotype.Component;
@Component
public class AOPAnnotationTestClient {
@MyAnnotation
public void test(){
System.out.println("正在測(cè)試AOP");
}
}測(cè)試類(lèi)代碼:
@Test
public void testAOPAnnotation(){
aopAnnotationTestClient.test();
}測(cè)試結(jié)果:

到此這篇關(guān)于SpringBoot項(xiàng)目使用aop的文章就介紹到這了,更多相關(guān)SpringBoot使用aop內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring?@Conditional通過(guò)條件控制bean注冊(cè)過(guò)程
- 向Spring IOC 容器動(dòng)態(tài)注冊(cè)bean實(shí)現(xiàn)方式
- 解決Springboot全局異常處理與AOP日志處理中@AfterThrowing失效問(wèn)題
- SpringBean和Controller實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)與注銷(xiāo)過(guò)程詳細(xì)講解
- BeanDefinitionRegistryPostProcessor如何動(dòng)態(tài)注冊(cè)Bean到Spring
- Spring運(yùn)行時(shí)動(dòng)態(tài)注冊(cè)bean的方法
- spring動(dòng)態(tài)注冊(cè)bean?AOP失效原理解析
相關(guān)文章
SpringBoot中的@ConditionalOnMissingBean注解使用詳解
這篇文章主要介紹了SpringBoot中的@ConditionalOnMissingBean注解使用詳解,@ConditionalOnMissingBean作用在@Bean定義上,也就是說(shuō)在容器加載它作用的Bean時(shí),檢查容器中是否存在目標(biāo)類(lèi)型,需要的朋友可以參考下2024-01-01
java實(shí)現(xiàn)解析二進(jìn)制文件的方法(字符串、圖片)
本篇文章主要介紹了java實(shí)現(xiàn)解析二進(jìn)制文件的方法(字符串、圖片),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
java 服務(wù)器接口快速開(kāi)發(fā)之servlet詳細(xì)教程
Servlet(Server Applet)是Java Servlet的簡(jiǎn)稱(chēng),稱(chēng)為小服務(wù)程序或服務(wù)連接器,用Java編寫(xiě)的服務(wù)器端程序,具有獨(dú)立于平臺(tái)和協(xié)議的特性,主要功能在于交互式地瀏覽和生成數(shù)據(jù),生成動(dòng)態(tài)Web內(nèi)容2021-06-06
Java中ThreadLocal線程變量的實(shí)現(xiàn)原理
本文主要介紹了Java中ThreadLocal線程變量的實(shí)現(xiàn)原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Springboot繼承Keycloak實(shí)現(xiàn)單點(diǎn)登錄與退出功能
這篇文章主要介紹了Springboot繼承Keycloak實(shí)現(xiàn)單點(diǎn)登陸與退出,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
zookeeper實(shí)戰(zhàn)之實(shí)現(xiàn)分布式鎖的方法
Zookeeper實(shí)現(xiàn)分布式鎖比Redis簡(jiǎn)單,Zookeeper有一個(gè)特性,多個(gè)線程在Zookeeper里創(chuàng)建同一個(gè)節(jié)點(diǎn)時(shí),只有一個(gè)線程執(zhí)行成功,Zookeeper主要是利用臨時(shí)有序節(jié)點(diǎn)這一特性實(shí)現(xiàn)分布式鎖,感興趣的朋友跟隨小編一起學(xué)習(xí)吧2022-11-11
Java基礎(chǔ)學(xué)習(xí)之方法的重載知識(shí)總結(jié)
今天帶大家來(lái)回顧Java基礎(chǔ)知識(shí),文中對(duì)Java方法的重載相關(guān)知識(shí)作了非常詳細(xì)的介紹,對(duì)正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下2021-05-05
Spring BeanPostProcessor接口使用詳解
本篇文章主要介紹了Spring BeanPostProcessor接口使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01

