SpringAOP
前言:
1.AOP定義? 用來干啥的? 怎么用?(怎么跑通它的思路)
代理模式
為啥要學代理模式? -- 因為是SpringAop的底層
原有的代碼不敢動,一動就是Bug,。所以使用代理可以做很多事,
- 在原有的基礎上,進行封裝一層,客戶使用的就我們這一層封裝后的功能
代理模式的分類:
- 靜態代理
-
角色分析:
- 抽象角色:一般用接口或者抽象類來解決,
- 真實角色:被代理的角色
- 代理角色:代理真實角色,代理真實角色后,我們一般做一些附屬操作
- 客戶:訪問代理角色的人
-
代理模式的好處:1.可以使真實角色的操作更加純粹!不用去關注一些公共的業務
- 2.公共的業務交給了代理角色--實現了業務的分工
- 3.業務發送擴展的時候,方便集中管理
-
缺點:
- 一個真實角色就會產生一個代理角色,代碼量翻倍---開發效率bian低
-
操作步驟---1,接口-->真實角色--》代理角色--》客戶端訪問代理
-
靜態代理這么麻煩,每次重寫人家的很多方法???---怎么解決代碼多---動態代理
-
個人理解代理:無非是在原有的基礎上,進行一層封裝,這樣既能使用被代理人的方法,也能實現自我的靈活安排!
-
動態代理
- 動態代理和靜態代理角色一樣
- 動態代理類是動態生成的,不是我們直接寫好的,,,想想直接將被代理人的很多方法都再次復述
- 動態代理分了兩大類---1.基於接口的動態代理---2.基於類的動態代理
- 基於接口---JDK動態代理 --- 注意,,,基於接口的!!!
- 基於類:cglib
- java字節碼:javasist
- 需要了解兩個類:Proxy,代理--InvocationHandler 調用處理程序 ----使用時:
- Proxy提供了創建動態代理類和實例的靜態方法,它也是由這些方法創建的所有動態代理類的超類。
- InvocationHandler接口提供的-newProxyInstance返回指定接口的代理類的實例,該接口將方法調用分派給指定的調用處理程序。
Proxy.newProxyInstance因為與IlegalArgumentException相同的原因而Proxy.getProxyClass.
-
它兩結合返回的proxyInstance---Proxy.newProxyInstance
-
至於被代理人方法,使用invoke操作
-
目的:生成一個代理對象,並執行被代理人方法
-
交互--被代理人方法,以及生成代理對象,提供一個調用代理人對象的方法
-
1.被代理人的方法的獲取,必須要獲取到被代理人的對象
-
2.生成代理對象,必須要依托於代理人的方法(接口)以及它的加載器(要不jvm處理不了)
-
建立一個動態代理
-
目的:生成一個代理對象,並執行被代理人方法
-
交互--被代理人方法,以及生成代理對象,提供一個調用代理人對象的方法
- 1.被代理人的方法的獲取,必須要獲取到被代理人的對象
- 2.生成代理對象,必須要依托於代理人的方法(接口)以及它的加載器(要不jvm處理不了)
package com.zjz.ProxyMethod; /* * 目的:生成一個代理對象,並執行被代理人方法 * 交互--被代理人方法,以及生成代理對象,提供一個調用代理人對象的方法 * 1.被代理人的方法的獲取,必須要獲取到被代理人的對象 * 2.生成代理對象,必須要依托於代理人的方法(接口)以及它的加載器(要不jvm處理不了) * * */ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { private Object target; // 被代理的人-對象 public void setTarget(Object target) { this.target = target; } // 調用代理人對象的方法,以及生成代理對象 public Object getProxy(){ Object proxyInstance = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); return proxyInstance; } // 被代理人方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("執行"+method.getName()+"方法---"); Object result = method.invoke(target, args); // 此時執行被代理人的方法 return result; } }
-
-
關於代理中為啥自動運行invoke,而且不可缺少
-
Proxy.newProxyInstance 執行時會生成一個創建出一個類$Proxy0,此類中調用invoke
-
如果少了還會執行,但是咱們的代理對象沒有方法了。。
Object result = method.invoke(被代理對象的接口, args); // 執行 被代理對象的接口方法,,invoke
AOP
每走一步,對照代理模式
介紹
- AOP(Aspect Oriented Programming)意為:面向切面編程,通過預編譯方式和運行期動態代理實現
程序功能的統一維護的一種技術。AOP是OOP的延續,是軟件開發中的一個熱點,也是Spring框架中的
一個重要內容,是函數式編程的一種衍生范型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使
得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
Aop在Spring中的作用
提供聲明式事務;允許用戶自定義切面
- 橫切關注點:跨越應用程序多個模塊的方法或功能。即是,與我們業務邏輯無關的,
但是我們需要關注的部分,就是橫切關注點。如日志 , 安全 , 緩存 , 事務等等 .... - 切面(ASPECT):橫切關注點 被模塊化 的特殊對象。即,它是一個類。
- 通知(Advice):切面必須要完成的工作。即,它是類中的一個方法。
- 目標(Target):被通知對象。
- 代理(Proxy):向目標對象應用通知之后創建的對象。
- 切入點(PointCut):切面通知 執行的 “地點”的定義。
- 連接點(JointPoint):與切入點匹配的執行點。
- SpringAOP中,通過Advice定義橫切邏輯,Spring中支持5種類型的Advice:
使用Spring實現Aop
-
1.導包
-
【重點】使用AOP織入,需要導入一個依賴包!
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
-
2.目的
- 1.切入的配置
- 切入的位置
- 注意:execution(* com.zjz.serivce.UserServiceImpl.*(..))
- 第一個表示所有...第二個切入的類,然后.之后應該是方法(..)表示所有方法..
- 注意:execution(* com.zjz.serivce.UserServiceImpl.*(..))
- 切入方法的加入
- 切入的位置
- 2.切入的編寫
- 三種方法...
- 1.切入的配置
使用Spring的API接口
目的:將日志,或者其它玩意,,切入到要執行的接口中
使用代理模式:怎么用? 你依據API寫好你要切的東西,然后交給ApplicationContext去做(定位!配置你寫的)
為啥交給間接管理員,服務者。。。你要在大的生態里整東西就是靠它。。
關鍵:ApplicationContext怎么做,,,,要切的東西怎么寫
-
要切的東西怎么寫;
- 1.要實現org.springframework.aop.下的接口 ---對應的Xml中要加對應的資源
- 2.直接使用它的方法(like-a) 擴展點就好了
-
配置:關鍵!!
- 1.約束,資源導入 aop的
-
2.aop配置
<aop:config>
中- 1.切入的位置 aop:pointcut
- 2.將我們的東西配進去 aop:advisor
<!--方式1,使用Spring API接口--> <!--配置AOP,需要導入AOP的約束--> <aop:config> <!--切入點 expression:表達式 execution(要執行的位置!* * * * *)--> <aop:pointcut id="pointcut" expression="execution(* com.zjz.serivce.UserServiceImpl.*(..))"/> <!-- 執行環繞增強!--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config>
自定義類來實現Aop
目的:將日志,或者其它玩意,,切入到要執行的接口中
使用代理模式:怎么用? 你寫好你要切的東西(自己編的),然后交給ApplicationContext去做(定位!配置你寫的)
為啥交給間接管理員,服務者。。。你要在大的生態里整東西就是靠它。。
關鍵:ApplicationContext怎么做,,,,要切的東西怎么寫
-
要切的東西怎么寫;
- 1.自己寫一個類,里面自己定義幾個方法---
public class DiyPointCut { public void before(){ System.out.println("=======方法執行前======="); } public void after(){ System.out.println("=======方法執行后======="); } }
-
配置
-
1.約束,資源導入 aop的
-
2.我們自己編寫bean導入,
-
3.aop配置
<aop:config>
中- 導入我們的配置,讓我們的寫的東西進行賦予方法
<aop:aspect ref="diy">
- 1.切入的位置 aop:pointcut
- 2.將我們的東西配進去 aop:before aop:after
<!--方式2:自定義類--> <bean id="diy" class="com.zjz.diy.DiyPointCut"/> <aop:config> <aop:aspect ref="diy"> <!--切入點--> <aop:pointcut id="point" expression="execution(* com.zjz.serivce.UserServiceImpl.*(..))"/> <!--通知--> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> </aop:config>
- 導入我們的配置,讓我們的寫的東西進行賦予方法
-
注解實現Aop
-
1.自己寫一個加注解的類
// 使用注解方式實現AOP @Aspect // 標注這個類是一個切面 public class AnnotationPointCut { @Before("execution(* com.zjz.serivce.UserServiceImpl.*(..))") public void before(){ System.out.println("======方法執行前====="); } @After("execution(* com.zjz.serivce.UserServiceImpl.*(..))") public void after(){ System.out.println("=====方法執行后====="); } // 在環繞增強中,我們可以給定一個參數,代表我們要處理切入的點 @Around("execution(* com.zjz.serivce.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint pj) throws Throwable { System.out.println("環繞前---"); // 獲得簽名 Signature signature = pj.getSignature(); System.out.println(signature); // 執行方法 Object proceed = pj.proceed(); System.out.println(proceed); System.out.println("環繞后---"); }
-
配置
-
1.約束,資源導入 aop的
-
2.我們自己編寫bean導入,
-
3.開啟注解支持
<!--方式3 注解配置-->
<bean id="annotationPointCut" class="com.zjz.diy.AnnotationPointCut"/>
<!--開啟注解支持-->
<aop:aspectj-autoproxy/>