日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

理解SpringAOP-菜鸟新手入门

發(fā)布時間:2023/12/2 javascript 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 理解SpringAOP-菜鸟新手入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

SpringFrameworkAOP學(xué)習(xí)筆記

  • 某一天
    • 筆記背景
    • 什么是AOP
      • JDK實例
    • 為什么AOP
    • java 動態(tài)代理
      • CGLib動態(tài)代理實例
    • JDK 動態(tài)代理與CGLib動態(tài)代理
    • 術(shù)語
    • AspectJ

某一天

文章內(nèi)容部分來自于
https://gitee.com/zhongfucheng/Java3y#spring%E5%AE%B6%E6%97%8F
http://c.biancheng.net/view/4241.html

筆記背景

本人在學(xué)習(xí)Spring玩轉(zhuǎn)全家桶時,發(fā)現(xiàn)自己對AOP以及切片編程等基礎(chǔ)Spring知識有些模糊不清,故寫翻看網(wǎng)上各種文章,網(wǎng)上文章有的抽象有的例子鮮明但是喧賓奪主,故還是我自己寫個文章梳理一下我自己學(xué)到的內(nèi)容

什么是AOP

面向切面編程(AOP)和面向?qū)ο缶幊?#xff08;OOP)類似,也是一種編程模式,全稱是“Aspect Oriented Programming”,使開發(fā)人員在編寫業(yè)務(wù)邏輯時可以專心于核心業(yè)務(wù),從而提高了開發(fā)效率。
目前最流行的 AOP 框架有兩個,分別為 Spring AOP 和 AspectJ

舉例說明

JDK實例

在包下 com.mengma.dao 創(chuàng)建CustomerDao 、CustomerDaoImpl的兩個類文件

package com.mengma.dao; public interface CustomerDao {public void add(); // 添加public void update(); // 修改public void delete(); // 刪除public void find(); // 查詢 }package com.mengma.dao; public class CustomerDaoImpl implements CustomerDao {@Overridepublic void add() {System.out.println("添加客戶...");}@Overridepublic void update() {System.out.println("修改客戶...");}@Overridepublic void delete() {System.out.println("刪除客戶...");}@Overridepublic void find() {System.out.println("修改客戶...");} }

在包 com.mengma.jdk 下,分別創(chuàng)建MyAspect、MyBeanFactory 、JDKProxyTest三個類

package com.mengma.jdk; public class MyAspect {public void myBefore() {System.out.println("方法執(zhí)行之前");}public void myAfter() {System.out.println("方法執(zhí)行之后");} }package com.mengma.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.mengma.dao.CustomerDao; import com.mengma.dao.CustomerDaoImpl; public class MyBeanFactory {public static CustomerDao getBean() {// 準(zhǔn)備目標(biāo)類final CustomerDao customerDao = new CustomerDaoImpl();// 創(chuàng)建切面類實例final MyAspect myAspect = new MyAspect();// 使用代理類,進行增強return (CustomerDao) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),new Class[] { CustomerDao.class }, new InvocationHandler() {public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {myAspect.myBefore(); // 前增強Object obj = method.invoke(customerDao, args);myAspect.myAfter(); // 后增強return obj;}});} }package com.mengma.jdk; import org.junit.Test; import com.mengma.dao.CustomerDao; public class JDKProxyTest {@Testpublic void test() {// 從工廠獲得指定的內(nèi)容(相當(dāng)于spring獲得,但此內(nèi)容時代理對象)CustomerDao customerDao = MyBeanFactory.getBean();// 執(zhí)行方法customerDao.add();customerDao.update();customerDao.delete();customerDao.find();} }

程序要想運行同樣需要上篇文章列出的5個spring包
結(jié)果如下

其中 Proxy 的 newProxyInstance() 方法的第一個參數(shù)是當(dāng)前類的類加載器,第二參數(shù)是所創(chuàng)建實例的實現(xiàn)類的接口,第三個參數(shù)就是需要增強的方法

上述例子是,JDK 動態(tài)代理,是通過 JDK 中的 java.lang.reflect.Proxy 類實現(xiàn)的

為什么AOP

Spring AOP主要做的事情就是:「把重復(fù)的代碼抽取,在運行的時候往業(yè)務(wù)方法上動態(tài)植入“切面類代碼”」

通過動態(tài)代理,我們可以把對象「增強」,將非業(yè)務(wù)代碼寫在要「增強」的邏輯上

完了以后,我們就可以通過「增強后的對象」去調(diào)用方法,最終屏蔽掉「重復(fù)代碼」

AOP編程可以簡單理解成:在執(zhí)行某些代碼前,執(zhí)行另外的代碼

其實Spring AOP的底層原理就是動態(tài)代理!Spring AOP使用純Java實現(xiàn),它不需要專門的編譯過程,也不需要特殊的類裝載器,它在運行期通過代理方式向目標(biāo)類織入增強代碼。在Spring中可以無縫地將Spring AOP、IoC和AspectJ整合在一起。

java 動態(tài)代理

在Java中動態(tài)代理有兩種方式:

JDK動態(tài)代理
上述例子就是jdk的動態(tài)代理,下面再舉例子說明CGLib動態(tài)代理

CGLib動態(tài)代理實例

在 com.mengma.dao 包下創(chuàng)建類 GoodsDao

package com.mengma.dao; public class GoodsDao {public void add() {System.out.println("添加商品...");}public void update() {System.out.println("修改商品...");}public void delete() {System.out.println("刪除商品...");}public void find() {System.out.println("修改商品...");} }

在 com.mengma.cglib 包下創(chuàng)建類 MyBeanFactory和CGLIBProxyTest

package com.mengma.cglib; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import com.mengma.dao.GoodsDao; import com.mengma.jdk.MyAspect; public class MyBeanFactory {public static GoodsDao getBean() {// 準(zhǔn)備目標(biāo)類final GoodsDao goodsDao = new GoodsDao();// 創(chuàng)建切面類實例final MyAspect myAspect = new MyAspect();// 生成代理類,CGLIB在運行時,生成指定對象的子類,增強Enhancer enhancer = new Enhancer();// 確定需要增強的類enhancer.setSuperclass(goodsDao.getClass());// 添加回調(diào)函數(shù)enhancer.setCallback(new MethodInterceptor() {// intercept 相當(dāng)于 jdk invoke,前三個參數(shù)與 jdk invoke—致@Overridepublic Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {myAspect.myBefore(); // 前增強Object obj = method.invoke(goodsDao, args); // 目標(biāo)方法執(zhí)行myAspect.myAfter(); // 后增強return obj;}});// 創(chuàng)建代理類GoodsDao goodsDaoProxy = (GoodsDao) enhancer.create();return goodsDaoProxy;} }package com.mengma.cglib; import org.junit.Test; import com.mengma.dao.GoodsDao; public class CGLIBProxyTest {@Testpublic void test() {// 從工廠獲得指定的內(nèi)容(相當(dāng)于spring獲得,但此內(nèi)容時代理對象)GoodsDao goodsDao = MyBeanFactory.getBean();// 執(zhí)行方法goodsDao.add();goodsDao.update();goodsDao.delete();goodsDao.find();} }

上述代碼中,應(yīng)用了 CGLIB 的核心類 Enhancer

intercept() 方法相當(dāng)于 JDK 動態(tài)代理方式中的 invoke() 方法,該方法會在目標(biāo)方法執(zhí)行的前后,對切面類中的方法進行增強;之后調(diào)用 Enhancer 類的 create() 方法創(chuàng)建代理類,最后將代理類返回

JDK 動態(tài)代理與CGLib動態(tài)代理

動態(tài)代理也有個約束:目標(biāo)對象一定是要有接口的,沒有接口就不能實現(xiàn)動態(tài)代理……----->因此出現(xiàn)了cglib代理

cglib代理也叫子類代理,從內(nèi)存中構(gòu)建出一個子類來擴展目標(biāo)對象的功能

Spring AOP默認是使用JDK動態(tài)代理,如果代理的類沒有接口則會使用CGLib代理

如果是單例的我們最好使用CGLib代理,如果是多例的我們最好使用JDK代理

JDK在創(chuàng)建代理對象時的性能要高于CGLib代理,而生成代理對象的運行性能卻比CGLib的低。

如果是單例的代理,推薦使用CGLib

看到這里我們就應(yīng)該知道什么是Spring AOP(面向切面編程)了:將相同邏輯的重復(fù)代碼橫向抽取出來,使用動態(tài)代理技術(shù)將這些重復(fù)代碼織入到目標(biāo)對象方法中,實現(xiàn)和原來一樣的功能

現(xiàn)在應(yīng)用更多更流行的是另一種方式@AspectJ注解驅(qū)動的切面

術(shù)語

連接點(Join point):

能夠被攔截的地方:Spring AOP是基于動態(tài)代理的,所以是方法攔截的。每個成員方法都可以稱之為連接點~

切點(Poincut):

具體定位的連接點:上面也說了,每個方法都可以稱之為連接點,我們具體定位到某一個方法就成為切點。

增強/通知(Advice):

表示添加到切點的一段邏輯代碼,并定位連接點的方位信息。

簡單來說就定義了是干什么的,具體是在哪干

Spring AOP提供了5種Advice類型給我們:前置、后置、返回、異常、環(huán)繞給我們使用!

org.springframework.aop.MethodBeforeAdvice(前置通知) 在方法之前自動執(zhí)行的通知稱為前置通知,可以應(yīng)用于權(quán)限管理等功能。
org.springframework.aop.AfterReturningAdvice(后置通知) 在方法之后自動執(zhí)行的通知稱為后置通知,可以應(yīng)用于關(guān)閉流、上傳文件、刪除臨時文件等功能。
org.aopalliance.intercept.MethodInterceptor(環(huán)繞通知) 在方法前后自動執(zhí)行的通知稱為環(huán)繞通知,可以應(yīng)用于日志、事務(wù)管理等功能。
org.springframework.aop.ThrowsAdvice(異常通知) 在方法拋出異常時自動執(zhí)行的通知稱為異常通知,可以應(yīng)用于處理異常記錄日志等功能。
org.springframework.aop.IntroductionInterceptor(引介通知) 在目標(biāo)類中添加一些新的方法和屬性,可以應(yīng)用于修改舊版本程序(增強類)。

織入(Weaving):

將增強/通知添加到目標(biāo)類的具體連接點上的過程。

引入/引介(Introduction):

引入/引介允許我們向現(xiàn)有的類添加新方法或?qū)傩浴J且环N特殊的增強!

切面(Aspect):

切面由切點和增強/通知組成,它既包括了橫切邏輯的定義、也包括了連接點的定義

AspectJ

使用 AspectJ 開發(fā) AOP 通常有兩種方式:
基于 XML 的聲明式
基于 Annotation 的聲明式

xml由于隨著bean增多,會特別臃腫,所以主流更多采用注解

xml存在錯誤,不知道怎么回事

注釋掉就可以正常運行了,不過注掉的事務(wù)代碼不了

所以下面是注解的樣例

package com.mengma.dao; public interface CustomerDao {public void add(); // 添加public void update(); // 修改public void delete(); // 刪除public void find(); // 查詢 }package com.mengma.dao; import org.springframework.stereotype.Repository;@Repository("customerDao") public class CustomerDaoImpl implements CustomerDao {@Overridepublic void add() {System.out.println("添加客戶...");}@Overridepublic void update() {System.out.println("修改客戶...");}@Overridepublic void delete() {System.out.println("刪除客戶...");}@Overridepublic void find() {System.out.println("修改客戶...");} }package com.aspectJ.annotation; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; //切面類 @Aspect @Component public class MyAspect {// 用于取代:<aop:pointcut// expression="execution(*com.mengma.dao..*.*(..))" id="myPointCut"/>// 要求:方法必須是private,沒有值,名稱自定義,沒有參數(shù)@Pointcut("execution(* com.mengma.dao..*.*(..))")private void myPointCut() {}// 前置通知@Before("myPointCut()")public void myBefore(JoinPoint joinPoint) {System.out.print("前置通知,目標(biāo):");System.out.print(joinPoint.getTarget() + "方法名稱:");System.out.println(joinPoint.getSignature().getName());}// 后置通知@AfterReturning(value = "myPointCut()")public void myAfterReturning(JoinPoint joinPoint) {System.out.print("后置通知,方法名稱:" + joinPoint.getSignature().getName());}// 環(huán)繞通知@Around("myPointCut()")public Object myAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable {System.out.println("環(huán)繞開始"); // 開始Object obj = proceedingJoinPoint.proceed(); // 執(zhí)行當(dāng)前目標(biāo)方法System.out.println("環(huán)繞結(jié)束"); // 結(jié)束return obj;}// 異常通知@AfterThrowing(value = "myPointCut()", throwing = "e")public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {System.out.println("異常通知" + "出錯了" + e.getMessage());}// 最終通知@After("myPointCut()")public void myAfter() {System.out.println("最終通知");} }package com.aspectJ.annotation; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.mengma.dao.CustomerDao;public class AnnotationTest {@Testpublic void test() {String xmlPath = "com/aspectJ/annotation/applicationContext.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);System.out.println(applicationContext);// 從spring容器獲取實例CustomerDao customerDao = (CustomerDao) applicationContext.getBean("customerDao");// 執(zhí)行方法customerDao.add();} } <?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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--掃描含com.mengma包下的所有注解--><context:component-scan base-package="com.mengma.dao"/><context:component-scan base-package="com.aspectJ.annotation"/><!-- 使切面開啟自動代理 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>

上述代碼中, @Aspect 注解用于聲明這是一個切面類,該類作為組件使用,所以要添加 @Component 注解才能生效。 @Poincut 注解用于配置切入點,取代 XML 文件中配置切入點的代碼。

在每個通知相應(yīng)的方法上都添加了注解聲明,并且將切入點方法名“myPointCut”作為參數(shù)傳遞給要執(zhí)行的方法,如需其他參數(shù)(如異常通知的異常參數(shù)),可以根據(jù)代碼提示傳遞相應(yīng)的屬性值。

導(dǎo)入了 AOP 命名空間及其配套的約束,使切面類中的 @Aspect注解能夠正常工作;

添加了掃描包,使注解生效;切面開啟自動代理。

總結(jié)

以上是生活随笔為你收集整理的理解SpringAOP-菜鸟新手入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。