javascript
这波 SpringFramework5.x 我先干了(AOP编程)
一、靜態代理設計模式
1.為什么需要代理設計模式
1.1問題
-
在JavaEE分層開發過程中,哪個層次對于我們來講最重要
DAO—>Service–>Controller
JavaEE分層開發中,最為重要的是Service Service業務層 -
Service層中包含了哪些代碼?
Service層中 =核心功能代碼(幾十行 上百行)+額外功能代碼(附加功能)1.核心功能業務運算DAO調用2.額外功能不屬于業務可有可無代碼量小例如:事務、日志、性能。。。 -
額外功能書寫在Service層中好不好?
Service層的調用者(controller):需要在Service層書寫額外功能軟件設計者:Service層不需要額外功能 -
現實生活中 的解決方式
2.代理設計模式
2.1概念通過代理類,為原始類(目標)增加額外功能
好處:利于原始類(目標)的維護2.2名詞解釋
1.目標類 原始類指的是 業務類(核心功能 --->業務運算 DAO調用)2.目標方法 原始方法目標類(原始類)中的方法 就是目標方法(原始方法)3.額外功能(附加功能) 日志,事務,性能2.3代理開發的核心要素
代理類=目標類(原始類)+額外功能+原始類(目標類)實現相同的接口 房東---->public interface UserService{m1(){}m2(){}}UserServiceImpl implements UserService{m1(){}m2(){}}2.4編碼
靜態代理: 為每一個原始類,手工編寫一個代理類(.java .class)
2.5靜態代理存在的問題
1.靜態類文件過多,不利于項目管理UserServiceImpl UserServiceProxyOrderServiceImpl OrderServiceProxy2.額外功能維護性差代理類中 額外功能修改復雜(麻煩)
二、Spring的動態代理開發
1.Spring動態代理的概念
概念:通過代理類為原始類(目標類)增加額外功能
好處:利于原始類(目標類)的維護
2.搭建開發環境
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.1.14.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.8</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.3</version></dependency>3.Spring動態代理的開發步驟
①創建原始對目標對象
②、額外功能
MethodBeforeAdvice接口
額外的功能書寫在接口的實現中,運行在原始方法之前運行額外功能
public class Before implements MethodBeforeAdvice {/*作用:需要把運行在原始方法執行之前運行的額外功能,書寫在before方法中*/@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println("======額外功能=====");} } <bean id="before" class="com.myspring.dynamic.Before" />③、定義切入點
切入點:額外功能加入的位置目的:由程序員根據自己的需要,決定額外功能加入給哪個原始方法 registe / longin 簡單的測試:所有方法都作為切入點都加入額外的功能。 <aop:config><!--定義切入的方式--><aop:pointcut id="pc" expression="execution(* *(..))"/></aop:config>④、組裝(②、③整合)
表達的含義:所有方法 都加入before的額外功能<aop:advisor advice-ref="before" pointcut-ref="pc"/> 這是④的完整配置<aop:config><!--定義切入的方式--><aop:pointcut id="pc" expression="execution(* *(..))"/><aop:advisor advice-ref="before" pointcut-ref="pc"/></aop:config>⑤、調用
目的:獲得Sporing工廠的動態代理對象,并進行調用ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");注意:1.Spring的工廠通過原始對象的id值獲得的是代理對象2.獲得代理對象后,可以通過聲明接口類型,進行對象的存儲UserService userService = applicationContext.getBean("userService", UserService.class);userService.login("bugz","123456");userService.register(new User("bugz","123456"));4.動態代理細節分析
①、Spring創建的動態代理類在那里?
Spring框架在運行時,通過動態字節碼技術,在JVM創建的,運行在JVM內部,等程序結束后,會和JVM一起消失。
————————————————————————————————————————————————————
什么叫動態字節碼技術:通過第三方動態字節碼框架,在JVM中創建對應類的字節碼,進而創建對象,當虛擬機結束,動態字節碼跟著消失。
—————————————————————————————————————————————————
結論:動態代理不需要定義類文件,都是JVM運行過程中動態創建的,所以不會造成靜態代理,類文件數量過多,影響項目管理的問題。
②、動態代理編程簡化代理的開發
在額外功能不變的前提下,創建其他目標類(原始類)的代理對象時,只需要指定原始(目標)對象即可。
③動態代理額外功能的維護性大大增強
三、Spring動態代理詳解
1.額外功能的詳解
- MethodBeforeAdvice分析
- MethodInterceptor(方法攔截器)
額外功能運行在原始代碼方法執行之后
@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {Object proceed = methodInvocation.proceed();System.out.println("+++++++++++額外功能運行在之后+++++++++");return proceed;}額外功能運行在原始代碼方法執行之前、之后。
什么樣的額外功能,運行在原始方法之前,之后都要添加? 例:事務@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("+++++++++++額外功能運行在之前+++++++++");Object proceed = methodInvocation.proceed();System.out.println("+++++++++++額外功能運行在之后+++++++++");return proceed;}額外功能運行在原始方法拋出異常的時候
@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {Object proceed = null;try {proceed = methodInvocation.proceed();} catch (Throwable throwable) {System.out.println("+++++++++++ 拋出異常時的 額外功能+++++++++");throwable.printStackTrace();}return proceed;}MethodInterceptor影響原始方法的返回值
原始方法的返回值,直接作為invoke方法的返回值返回,MethodInterceptor不會影響原始方法的返回值 MethodInterceptor影響原始方法的返回值 Invoke方法的返回值,不要直接返回原始方法的運行結果即可。@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("+++++++++++額外功能+++++++++");Object proceed = methodInvocation.proceed();return false;}2.切入點詳解
切入點決定額外功能加入位置(方法) <aop:pointcut id="pc" expression="execution(* *(..))"/> execution(* *(..)) --->匹配了所有方法 a b c1.execution() 切入點函數 2.* *(..) 切入點表達式2.1切入點表達式
①、方法切入點表達式
- 定義login方法的切入點* login(..) #定義register作為切入點 * register(..)
- 定義long方法且login方法有兩個字符串類型的參數 作為切入點* login(String,String) #注意:非Java.lang包中的類型,必須要寫全限定名 * register(com.xxx.xxx.User) # ..可以和具體的參數類型連用 * login(String,..) -> login(String)/login(String,String)/login(String,com.xxx.User)
- 精準方法切入點限定修飾符 返回值 包.類.方法(參數) * com.xxx.xxx.login() * com.xxx.xxx.login(String,String)
②、類切入點
指定特定類作為切入點(額外功能加入的位置),自然這個類中的所有方法,都會加上額外的功能
- 語法1#類中所有的方法加入了額外功能 * com.xx.xx.UserServiceImpl.*(..)
- 語法2 #忽略包1.類只存在一級包 com.UserServiceImpl* *.UserServiceImpl.*(..)2.類存在多級包 com.xxx.xxx.xxx.UserServiceImpl* *..UserServiceImpl.*(..)
③、包切入點 實戰
指定包作為額外功能加入的位置,自然包中所有類及其方法都會加入額外功能
-
語法1
#切入包中的所有類,必須在xxx中,不能在xxx包的子包中 * com.a.xxx.*.*(..) -
語法2
#切入點當前包及其子包都生效 * com.a.xxx..*.*(..)
2.2切入點函數
切入點函數:用于執行切入點表達式
①、execution
最為重要的切入點函數,功能最全 執行 方法切入點表達式 類切入點表達式 包切入點表達式弊端:execution執行切入點表達式,書寫麻煩execution(* com.xxx.xxx..*.*(..)) 注意: 其他的切入點函數 簡化execution書寫復雜度,功能上完全一致②、args
作用:主要用于函數(方法)參數的匹配 切入點:例如---方法參數必須得是2個字符串類型的參數execution(* *(String,String))args(String,String)③、within
作用:主要用于進行類、包切入點表達式的匹配 切入點:UserServiceImpl這個類execution(* *..UserServiceImpl.*(..))within(*..UserServiceImpl)execution(* com.xx.xx..*.*(..))within(com.xx.xx..*)④、@annotation
作用:為具有特殊注解的方法加入額外功能 <aop:pointcut id="pc" expression="@annotation(com.xx.Log)"/>⑤、切入點函數的邏輯運算
指的是整合多個切入點函數一起配合工作,進而完成更為復雜的需求
- and與操作
- or或操作
四、AOP編程
1.AOP編程
AOP(Aspect Oriented Programming) 面向切面編程 = Spring動態代理開發
以切面為基本單位的程序開發,通過切面間的彼此協同,相互調用,完成程序的構建
切面 = 切入點+額外功能
OOP(Object Oriented Programming) 面向對象編程 JAVA
以對象為基本單位的程序開發,通過對象間的彼此協同,相互調用,完成程序的構建
POP(Procedure Oriented Programming) 面向過程(方法、函數)編程 c語言
以過程為單位的程序開發,通過過程間的彼此協同,相互調用,完成程序的構建。
AOP的概念:本質就是Spring的動態代理開發,通過代理類為原始類增加額外功能。
好處:利于原始類的維護
注意:AOP編程不可能取代OOP,OOP編程有意補充。
2.AOP編程的開發步驟
1.原始對象
2.額外功能(MethodInterceptor)
3.切入點
4.組裝切面(額外功能+切入點)
3.切面的名詞解釋
切面 = 切入點+額外功能
幾何學:面=點+相同性質
五、AOP底層實現原理
1.核心問題
1.AOP如何創建動態代理類(動態字節碼技術) 2.Spring工廠如何加工創建代理類對象通過原始類對象的id值,獲得的是代理對象2.動態代理類的創建
2.1、JDK的動態代理
- Proxy.newProxyInstance方法參數詳解
- 編碼
2.2 CGlib動態代理
CGlib創建動態代理的原理:父子繼承關系創建代理對象,原始類作為父類,代理類作為子類,這樣既可以保證二者方法一致,同時在代理類中提供新的實現(額外功能+原始方法)
- 編碼
- 總結
1.JDK動態代理 Proxy.newProxyInstance() ------------通過接口創建代理的實現類
2.Cglib動態代理 Enhancer---------------------------------通過繼承父類創建代理類
3.Spring工廠如何加工原始對象
- 思路分析
- 編碼
六、基于注解的AOP編程
1.基于注解的AOP開發步驟
1.原始對象
2.額外功能
3.切入點
4.組裝切面
2.切入點復用
(1)切入點復用
(2)、動態代理的創建方式
AOP底層實現 2種代理創建方式 1.JDK 通過實現接口 做新的實現類方式 創建代理對象 2.Cglib 通過繼承父類 做新的子類 創建代理對象默認情況 AOP編程底層應用JDK動態代理創建方式 如果切換Cglib1.基于注解AOP開發<aop:aspectj-autoproxy proxy-target-class="true"/>2.傳統的AOP開發<aop:config proxy-target-class="true"></aop:config>七、AOP開發中的一個坑
坑:在同一個業務類中,進行業務方法間的相互調用,只有最外層的方法,才是加入了額外功能(內部的方法,通過普通的方式調用,都調用的是原始方法)。如果想讓內層的方法也調用代理對象的方法,就要ApplicationContextAware獲得工廠,進而獲得代理對象。 public class UserServiceImpl implements UserService, ApplicationContextAware {private ApplicationContext ctx;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.ctx = applicationContext;}@Overridepublic void register(User user) {System.out.println("UserServiceImpl.register");/*調用的是原始方法的login方法--->核心功能設計的目的:代理對象的log方法 ——————>額外功能+核心功能ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("/applicationContext2.xml");UserService userService =(UserService) classPathXmlApplicationContext.getBean("userService");userService.login();Spring工廠重量級資源 一個應用中 應該只創建一個工廠*/UserService userService = (UserService) ctx.getBean("userService");userService.login("bugz", "123444");}@Overridepublic void login(String name, String password) {System.out.println("UserServiceImpl.login");} }八、AOP階段知識總結
總結
以上是生活随笔為你收集整理的这波 SpringFramework5.x 我先干了(AOP编程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 后天网选
- 下一篇: 教程篇(7.2) 02. 防火墙策略