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

歡迎訪問 生活随笔!

生活随笔

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

javascript

Spring-AOP实现的两种方式

發(fā)布時(shí)間:2025/3/19 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring-AOP实现的两种方式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

AOP常用的實(shí)現(xiàn)方式有兩種,一種是采用聲明的方式來實(shí)現(xiàn)(基于XML),一種是采用注解的方式來實(shí)現(xiàn)(基于AspectJ)

首先復(fù)習(xí)下AOP中一些比較重要的概念:

Joinpoint(連接點(diǎn)):程序執(zhí)行時(shí)的某個(gè)特定的點(diǎn),在Spring中就是某一個(gè)方法的執(zhí)行 。
Pointcut(切點(diǎn)):說的通俗點(diǎn),spring中AOP的切點(diǎn)就是指一些方法的集合,而這些方法是需要被增強(qiáng)、被代理的。一般都是按照一定的約定規(guī)則來表示的,如正則表達(dá)式等。切點(diǎn)是由一類連接點(diǎn)組成。?
Advice(通知):還是說的通俗點(diǎn),就是在指定切點(diǎn)上要干些什么。?
Advisor(通知器):其實(shí)就是切點(diǎn)和通知的結(jié)合 。

一、基于XML配置的Spring AOP

采用聲明的方式實(shí)現(xiàn)(在XML文件中配置),大致步驟為:配置文件中配置pointcut, 在java中用編寫實(shí)際的aspect 類, 針對(duì)對(duì)切入點(diǎn)進(jìn)行相關(guān)的業(yè)務(wù)處理。

業(yè)務(wù)接口:

package com.spring.service;public interface IUserManagerService {//查找用戶public String findUser();//添加用戶public void addUser(); }

業(yè)務(wù)實(shí)現(xiàn):

package com.spring.service.impl;import com.spring.service.IUserManagerService;public class UserManagerServiceImpl implements IUserManagerService{private String name;public void setName(String name){this.name=name;}public String getName(){return this.name;}public String findUser(){System.out.println("============執(zhí)行業(yè)務(wù)方法findUser,查找的用戶是:"+name+"=============");return name;}public void addUser(){System.out.println("============執(zhí)行業(yè)務(wù)方法addUser=============");//throw new RuntimeException();} }

切面類:

package com.spring.aop;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint;public class AopAspect {/*** 前置通知:目標(biāo)方法調(diào)用之前執(zhí)行的代碼* @param jp*/public void doBefore(JoinPoint jp){System.out.println("===========執(zhí)行前置通知============");}/*** 后置返回通知:目標(biāo)方法正常結(jié)束后執(zhí)行的代碼* 返回通知是可以訪問到目標(biāo)方法的返回值的* @param jp* @param result*/public void doAfterReturning(JoinPoint jp,String result){System.out.println("===========執(zhí)行后置通知============");System.out.println("返回值result==================="+result);}/*** 最終通知:目標(biāo)方法調(diào)用之后執(zhí)行的代碼(無論目標(biāo)方法是否出現(xiàn)異常均執(zhí)行)* 因?yàn)榉椒赡軙?huì)出現(xiàn)異常,所以不能返回方法的返回值* @param jp*/public void doAfter(JoinPoint jp){System.out.println("===========執(zhí)行最終通知============");}/*** * 異常通知:目標(biāo)方法拋出異常時(shí)執(zhí)行的代碼* 可以訪問到異常對(duì)象* @param jp* @param ex*/public void doAfterThrowing(JoinPoint jp,Exception ex){System.out.println("===========執(zhí)行異常通知============");}/*** 環(huán)繞通知:目標(biāo)方法調(diào)用前后執(zhí)行的代碼,可以在方法調(diào)用前后完成自定義的行為。* 包圍一個(gè)連接點(diǎn)(join point)的通知。它會(huì)在切入點(diǎn)方法執(zhí)行前執(zhí)行同時(shí)方法結(jié)束也會(huì)執(zhí)行對(duì)應(yīng)的部分。* 主要是調(diào)用proceed()方法來執(zhí)行切入點(diǎn)方法,來作為環(huán)繞通知前后方法的分水嶺。* * 環(huán)繞通知類似于動(dòng)態(tài)代理的全過程:ProceedingJoinPoint類型的參數(shù)可以決定是否執(zhí)行目標(biāo)方法。* 而且環(huán)繞通知必須有返回值,返回值即為目標(biāo)方法的返回值* @param pjp* @return* @throws Throwable*/public Object doAround(ProceedingJoinPoint pjp) throws Throwable{System.out.println("======執(zhí)行環(huán)繞通知開始=========");// 調(diào)用方法的參數(shù)Object[] args = pjp.getArgs();// 調(diào)用的方法名String method = pjp.getSignature().getName();// 獲取目標(biāo)對(duì)象Object target = pjp.getTarget();// 執(zhí)行完方法的返回值// 調(diào)用proceed()方法,就會(huì)觸發(fā)切入點(diǎn)方法執(zhí)行Object result=pjp.proceed();System.out.println("輸出,方法名:" + method + ";目標(biāo)對(duì)象:" + target + ";返回值:" + result);System.out.println("======執(zhí)行環(huán)繞通知結(jié)束=========");return result;} }

Spring配置:

<?xml version="1.0" encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><!-- 聲明一個(gè)業(yè)務(wù)類 --><bean id="userManager" class="com.spring.service.impl.UserManagerServiceImpl"><property name="name" value="lixiaoxi"></property></bean> <!-- 聲明通知類 --><bean id="aspectBean" class="com.spring.aop.AopAspect" /><aop:config><aop:aspect ref="aspectBean"><aop:pointcut id="pointcut" expression="execution(* com.spring.service.impl.UserManagerServiceImpl..*(..))"/><aop:before method="doBefore" pointcut-ref="pointcut"/> <aop:after-returning method="doAfterReturning" pointcut-ref="pointcut" returning="result"/><aop:after method="doAfter" pointcut-ref="pointcut" /> <aop:around method="doAround" pointcut-ref="pointcut"/> <aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut" throwing="ex"/></aop:aspect></aop:config> </beans>

測(cè)試類:

package com.spring.test;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;import com.spring.service.IUserManagerService;public class TestAop {public static void main(String[] args) throws Exception{ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext3.xml");IUserManagerService userManager = (IUserManagerService)act.getBean("userManager");userManager.findUser();System.out.println("\n");userManager.addUser();} }

測(cè)試結(jié)果:

?二、使用注解配置AOP

采用注解來做aop, 主要是將寫在spring 配置文件中的連接點(diǎn)寫到注解里面。

業(yè)務(wù)接口和業(yè)務(wù)實(shí)現(xiàn)與上邊一樣,具體切面類如下:

package com.spring.aop;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;@Aspect public class AopAspectJ {/** * 必須為final String類型的,注解里要使用的變量只能是靜態(tài)常量類型的 */ public static final String EDP="execution(* com.spring.service.impl.UserManagerServiceImpl..*(..))";/*** 切面的前置方法 即方法執(zhí)行前攔截到的方法* 在目標(biāo)方法執(zhí)行之前的通知* @param jp*/@Before(EDP)public void doBefore(JoinPoint jp){System.out.println("=========執(zhí)行前置通知==========");}/*** 在方法正常執(zhí)行通過之后執(zhí)行的通知叫做返回通知* 可以返回到方法的返回值 在注解后加入returning * @param jp* @param result*/@AfterReturning(value=EDP,returning="result")public void doAfterReturning(JoinPoint jp,String result){System.out.println("===========執(zhí)行后置通知============");}/*** 最終通知:目標(biāo)方法調(diào)用之后執(zhí)行的通知(無論目標(biāo)方法是否出現(xiàn)異常均執(zhí)行)* @param jp*/@After(value=EDP)public void doAfter(JoinPoint jp){System.out.println("===========執(zhí)行最終通知============");}/*** 環(huán)繞通知:目標(biāo)方法調(diào)用前后執(zhí)行的通知,可以在方法調(diào)用前后完成自定義的行為。* @param pjp* @return* @throws Throwable*/@Around(EDP)public Object doAround(ProceedingJoinPoint pjp) throws Throwable{System.out.println("======執(zhí)行環(huán)繞通知開始=========");// 調(diào)用方法的參數(shù)Object[] args = pjp.getArgs();// 調(diào)用的方法名String method = pjp.getSignature().getName();// 獲取目標(biāo)對(duì)象Object target = pjp.getTarget();// 執(zhí)行完方法的返回值// 調(diào)用proceed()方法,就會(huì)觸發(fā)切入點(diǎn)方法執(zhí)行Object result=pjp.proceed();System.out.println("輸出,方法名:" + method + ";目標(biāo)對(duì)象:" + target + ";返回值:" + result);System.out.println("======執(zhí)行環(huán)繞通知結(jié)束=========");return result;}/*** 在目標(biāo)方法非正常執(zhí)行完成, 拋出異常的時(shí)候會(huì)走此方法* @param jp* @param ex*/@AfterThrowing(value=EDP,throwing="ex")public void doAfterThrowing(JoinPoint jp,Exception ex) {System.out.println("===========執(zhí)行異常通知============");} }

spring的配置:

<?xml version="1.0" encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><!-- 聲明spring對(duì)@AspectJ的支持 --><aop:aspectj-autoproxy/> <!-- 聲明一個(gè)業(yè)務(wù)類 --><bean id="userManager" class="com.spring.service.impl.UserManagerServiceImpl"><property name="name" value="lixiaoxi"></property></bean> <!-- 聲明通知類 --><bean id="aspectBean" class="com.spring.aop.AopAspectJ" /></beans>

測(cè)試類:

package com.spring.test;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;import com.spring.service.IUserManagerService;public class TestAop1 {public static void main(String[] args) throws Exception{ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext4.xml");IUserManagerService userManager = (IUserManagerService)act.getBean("userManager");userManager.findUser();System.out.println("\n");userManager.addUser();} }

測(cè)試結(jié)果與上面相同。

注意:
1.環(huán)繞方法通知,環(huán)繞方法通知要注意必須給出調(diào)用之后的返回值,否則被代理的方法會(huì)停止調(diào)用并返回null,除非你真的打算這么做。???????????
2.只有環(huán)繞通知才可以使用JoinPoint的子類ProceedingJoinPoint,各連接點(diǎn)類型可以調(diào)用代理的方法,并獲取、改變返回值。

補(bǔ)充:
1.<aop:pointcut>如果位于<aop:aspect>元素中,則命名切點(diǎn)只能被當(dāng)前<aop:aspect>內(nèi)定義的元素訪問到,為了能被整個(gè)<aop:config>元素中定義的所有增強(qiáng)訪問,則必須在<aop:config>下定義切點(diǎn)。
2.如果在<aop:config>元素下直接定義<aop:pointcut>,必須保證<aop:pointcut>在<aop:aspect>之前定義。<aop:config>下還可以定義<aop:advisor>,三者在<aop:config>中的配置有先后順序的要求:首先必須是<aop:pointcut>,然后是<aop:advisor>,最后是<aop:aspect>。而在<aop:aspect>中定義的<aop:pointcut>則沒有先后順序的要求,可以在任何位置定義。
.<aop:pointcut>:用來定義切入點(diǎn),該切入點(diǎn)可以重用;
.<aop:advisor>:用來定義只有一個(gè)通知和一個(gè)切入點(diǎn)的切面;
.<aop:aspect>:用來定義切面,該切面可以包含多個(gè)切入點(diǎn)和通知,而且標(biāo)簽內(nèi)部的通知和切入點(diǎn)定義是無序的;和advisor的區(qū)別就在此,advisor只包含一個(gè)通知和一個(gè)切入點(diǎn)。
3.在使用spring框架配置AOP的時(shí)候,不管是通過XML配置文件還是注解的方式都需要定義pointcut"切入點(diǎn)"
例如定義切入點(diǎn)表達(dá)式?execution(* com.sample.service.impl..*.*(..))
execution()是最常用的切點(diǎn)函數(shù),其語法如下所示:
整個(gè)表達(dá)式可以分為五個(gè)部分:
(1)、execution(): 表達(dá)式主體。
(2)、第一個(gè)*號(hào):表示返回類型,*號(hào)表示所有的類型。
(3)、包名:表示需要攔截的包名,后面的兩個(gè)句點(diǎn)表示當(dāng)前包和當(dāng)前包的所有子包,com.sample.service.impl包、子孫包下所有類的方法。
(4)、第二個(gè)*號(hào):表示類名,*號(hào)表示所有的類。
(5)、*(..):最后這個(gè)星號(hào)表示方法名,*號(hào)表示所有的方法,后面括弧里面表示方法的參數(shù),兩個(gè)句點(diǎn)表示任何參數(shù)。

總結(jié)

以上是生活随笔為你收集整理的Spring-AOP实现的两种方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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