手機怎樣制作網頁免費seo診斷
一、Spring AOP 簡介
1.概述
-
對于spring來說,有三大組件,IOC,ID,AOP
-
aop概述:AOP(Aspect Oriented Programming)面向切面編程。
-
作用:不改變原有代碼設計的基礎上實現功能增強
-
例子
-
傳統打印日志
-
使用AOP增強之后
-
-
2.代理模式
- 如果沒有聽過代理模式,點擊鏈接先學習代理模式 : https://www.bilibili.com/video/BV1tY411Z799/?share_source=copy_web&vd_source=fdccda7d1272a2e0f49cadca354a5073
- 靜態(tài)代理
- 動態(tài)代理
- jdk 動態(tài)代理
- cglib 動態(tài)代理
二、AOP概念
1.案例分析
-
創(chuàng)建類提供增刪改查方法,實現事務增強操作功能
public interface IStudentService {void save(Student student);int update(Student student);Student queryStudentById(Long id); }
-
接口實現類
public class StudentServiceImpl implements IStudentService {public void save(Student student) { // System.out.println("開啟事務");System.out.println("保存操作"); // System.out.println("關閉事務");}public int update(Student student) { // System.out.println("開啟事務");System.out.println("更新操作"); // System.out.println("關閉事務");return 0;}public Student queryStudentById(Long id) {System.out.println("查詢操作");return null;} }
-
提供通知類
public class TransactionAdvice {public void before(){System.out.println("開啟事務");}public void after(){System.out.println("關閉事務");}public void invoke(){before();//具體的業(yè)務執(zhí)行after();} }
2.核心概念
2.1概念
- 連接點(JoinPoint):對于需要增強的方法就是連接點
- 切入點(Pointcut):需要增強的方法是切入點,匹配連接點的式子
- 通知(Advice):存放需要增強功能的共性代碼,就叫通知
- 切面(Aspect):通知是需要增強的功能存在多個,切入點是需要增強的方法也存在多個,需要去給切入點和通知做關聯,知道哪個切入點對應哪個通知,這種描述關系就叫切面
- 通知類:存放通知(方法)的類
2.2圖示
3.核心概念
- 目標對象 target
- 代理 proxy
三、通過注解實現AOP配置
1.導入依賴
-
導入aop依賴
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.17.RELEASE</version> </dependency>
-
導入Spring依賴
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.17.RELEASE</version> </dependency>
2.配置AOP支持
-
@EnableAspectJAutoProxy
-
說明
名稱 @EnableAspectJAutoProxy 使用位置 配置類上 作用 開啟注解的aop支持 -
代碼
@Configuration @EnableAspectJAutoProxy @ComponentScan("cn.sycoder") public class AppConfig { }
3.創(chuàng)建切面類
-
@Aspect
-
說明
名稱 @Aspect 作用 設置當前類為切面類 使用位置 類上 屬性 String value() default “”;可以給切面指定名稱 -
@Pointcut
-
說明
名稱 @Pointcut 作用 設置切入點方法 使用位置 方法上 屬性 String value() default “”;切入點表達式 -
代碼
@Component @Aspect public class TransactionAdvice {//定義通知 綁定切點和通知的關系@Before("pc()")public void before(){System.out.println("開啟事務");}@After("pc()")public void after(){System.out.println("關閉事務");}//定義切點@Pointcut("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){} }
4.測試aop
-
測試代碼
@Testpublic void testAop(){AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);IStudentService bean = applicationContext.getBean(IStudentService.class);bean.save(null);}
-
打印輸出
-
5.各種通知
5.1@Before
-
前置通知:被代理的目標方法執(zhí)行前執(zhí)行
-
說明
名稱 @Before 使用位置 方法上 作用 前置通知,目標方法執(zhí)行前執(zhí)行 屬性 String value(); 切入點表達式 可以提供的入參 JoinPoint joinPoint ,切點 -
使用
@Before("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))") public void before(JoinPoint joinPoint){System.out.println("開啟事務"); }
5.2@After
-
后置通知:被代理的目標方法執(zhí)行后執(zhí)行
-
說明
名稱 @After 使用位置 方法上 作用 后置通知:被代理的目標方法執(zhí)行后執(zhí)行 屬性 String value(); 切入點表達式 可以提供的入參 JoinPoint joinPoint ,切點 -
使用
@After("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))") public void after(){System.out.println("關閉事務"); }
5.3@AfterReturning
-
返回通知:被代理的目標方法成功結束后執(zhí)行
-
說明
名稱 @AfterReturning 使用位置 方法上 作用 返回通知:被代理的目標方法成功結束后執(zhí)行 屬性 String value(); 切入點表達式,String returning();方法返回值 可以提供的入參 JoinPoint joinPoint ,切點,方法返回值 obj -
使用
- 如果想要得到返回值,需要在注解上添加參數returning名稱,對應方法參數名稱
- 切面表達式的返回值為*而不是void
@AfterReturning(returning = "obj",value = "execution(* cn.sycoder.service.impl.StudentServiceImpl.update(..))") public void afterReturning(JoinPoint joinPoint,Object obj){System.out.println(obj);System.out.println("返回通知"); }
5.4@AfterThrowing
-
異常通知:被代理的目標方法出現異常后執(zhí)行
-
說明
名稱 @AfterThrowing 使用位置 方法上 作用 異常通知:被代理的目標方法出現異常后執(zhí)行 屬性 String value(); 切入點表達式String throwing();異常返回 可以提供的入參 JoinPoint joinPoint ,切點,異常返回值 th -
使用
@AfterThrowing(throwing = "th",value = "execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))") public void afterThrowing(JoinPoint pointcut,Throwable th){System.out.println("異常通知"); }
5.5@Around
-
環(huán)繞通知:可以使用 try 代碼塊把被代理的目標方法圍繞住,就可以做自己想做的操作,可以在里面做任何的操作
-
說明
名稱 @Around 使用位置 方法上 作用 異常通知:被代理的目標方法出現異常后執(zhí)行 屬性 String value(); 切入點表達式 可以提供的入參 ProceedingJoinPoint joinPoint,可以通過該對象調用原始方法 -
使用
@Around("execution(void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void around(ProceedingJoinPoint joinPoint){try{System.out.println("前置通知");Object proceed = joinPoint.proceed();//執(zhí)行目標方法System.out.println("返回通知");}catch (Exception e){e.printStackTrace();} catch (Throwable throwable) {System.out.println("異常通知");throwable.printStackTrace();} finally {}}
5.6各種通知執(zhí)行順序
- 環(huán)繞通知—前置通知—目標方法—返回通知或異常通知—后置通知
6.切入點表達式
-
概述:切入點表達式是用來尋找目標代理方法的
execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..))
-
圖示
-
表達式實操
編號 名稱 使用位置 作用 1 * 代替權限修飾符和返回值 表示任意權限和返回 2 * 使用到包位置 一個*表示當前一層的任意 3 *… 使用到包位置 任意包任意類 4 * 使用到類 表示任意類 5 *Service 使用到類 表示尋找以Service 結尾的任意接口或類 6 … 使用到參數 表示任意參數 -
案例:找到實現類中的任意save方法
execution(* cn.sycoder.service.impl.StudentServiceImpl.save(..))
-
案例:sycoder 包下面的類中的任意update 方法
execution(* cn.sycoder.*.update(..))
-
案例:找到sycoder 包下面及其任意子包中的任意update 方法
execution(* cn.sycoder.*..update(..))
-
案例:找到service 下面任意類的update 方法
execution(* cn.sycoder.service.*.update(..))
-
案例:找到以Service 結尾的接口或者類的update 方法
execution(* cn.sycoder.service.*Service.update(..))
-
案例:找到Service 結尾的接口或者類的update 方法,任意參數的
execution(* cn.sycoder.service.*Service.update(..))
-
-
注意:如果你切的越模糊,那性能就會越低,所以實際開發(fā)中,建議把范圍切小一點
-
優(yōu)先級
- 如果想手動指定優(yōu)先級關系,可以使用@Order(1)注解
- 提供的值越小,優(yōu)先級越高
- 如果想手動指定優(yōu)先級關系,可以使用@Order(1)注解
-
重用切入點表達式
-
定義切點
@Component @Aspect public class TransactionAdvice {//定義切點@Pointcut("execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){System.out.println("----切點");} }
-
在其他切面類通知里面重用切點
@Component @Aspect public class LogAdvice {@Before("cn.sycoder.advice.TransactionAdvice.pc()")public void log(){System.out.println("-0-----這里是打印日志");} }
-
切面內部自己重用
@Component @Aspect public class TransactionAdvice {//定義切點@Pointcut("execution(public void cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void pc(){System.out.println("----切點");}//定義通知 綁定切點和通知的關系//前置通知@Before("pc()")public void before(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();System.out.println(name);System.out.println("開啟事務");}
-
7.獲取通知相關信息
-
獲取連接點信息,在通知方法中添加參數 JoinPoint 即可
@Before("pc()") public void before(JoinPoint joinPoint){String name = joinPoint.getSignature().getName();System.out.println(name);System.out.println("開啟事務"); }
-
獲取目標方法返回值
- 使用AfterReturning 中的 returning 屬性,這里指定的名稱即是我們方法傳入的名稱
@AfterReturning(returning = "obj",value = "pc()")public void afterReturning(JoinPoint joinPoint,Object obj){System.out.println(obj);System.out.println("返回通知");}
-
獲取異常
- 使用AfterThrowing 中的 throwing 屬性,這里指定的名稱即是我們方法傳入的參數名稱
@AfterThrowing(throwing = "th",value = "execution(* cn.sycoder.service.impl.StudentServiceImpl.save(..))")public void afterThrowing(JoinPoint pointcut,Throwable th){System.out.println("異常通知");}
-
如果使用環(huán)繞通知
- 使用ProceedingJoinPoint joinPoint
@Around("execution(void cn.sycoder.service.*..save(..))")public void around(ProceedingJoinPoint joinPoint){try{System.out.println("環(huán)繞通知"); // System.out.println("前置通知");Object proceed = joinPoint.proceed();//執(zhí)行目標方法 // System.out.println("返回通知");}catch (Exception e){e.printStackTrace();} catch (Throwable throwable) { // System.out.println("異常通知");throwable.printStackTrace();} finally {}}
四、XML配置AOP
1.導入依賴
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.17.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.17.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><!-- <scope>test</scope>--></dependency>
2.基本準備
-
創(chuàng)建 service 接口以及方法
public interface IStudentService {void save(Student student); }
public class StudentServiceImpl implements IStudentService {public void save(Student student) {System.out.println("保存操作");} }
-
創(chuàng)建切面類
public class XmlAspect {public void before(){System.out.println("前置通知");}public void pointCut(){}public void after(JoinPoint joinPoint){System.out.println("后置通知");}public void afterReturning(Object obj){System.out.println("返回通知"+obj);}public void afterThrowing(Throwable t){System.out.println("異常通知");} }
3.創(chuàng)建xml 配置文件
-
aop.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="service" class="cn.sycoder.service.impl.StudentServiceImpl"></bean><bean id="xmlAspect" class="cn.sycoder.aspect.XmlAspect"></bean><aop:aspectj-autoproxy/><aop:config> <!-- 配置切面類--><aop:aspect ref="xmlAspect"> <!-- 配置切點--><aop:pointcut id="pc" expression="execution(* cn.sycoder.service.*..*(..))"/> <!-- 配置前置通知--><aop:before method="before" pointcut-ref="pc"></aop:before> <!-- 配置后置通知--><aop:after method="after" pointcut-ref="pc"></aop:after> <!-- 配置返回通知--><aop:after-returning method="afterReturning" returning="obj" pointcut-ref="pc"></aop:after-returning> <!-- 異常通知--><aop:after-throwing method="afterThrowing" throwing="t" pointcut-ref="pc"></aop:after-throwing></aop:aspect></aop:config> </beans>
4.總結
- 以后在公司使用注解的方式最流行,所以,xml 配置作為了解內容即可