<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring系列之AOP實(shí)現(xiàn)的兩種方式

          共 7673字,需瀏覽 16分鐘

           ·

          2020-09-11 05:13


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


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


          Joinpoint(連接點(diǎn)):程序執(zhí)行時(shí)的某個(gè)特定的點(diǎn),在Spring中就是某一個(gè)方法的執(zhí)行 。


          Pointcut(切點(diǎn)):說(shuō)的通俗點(diǎn),spring中AOP的切點(diǎn)就是指一些方法的集合,而這些方法是需要被增強(qiáng)、被代理的。一般都是按照一定的約定規(guī)則來(lái)表示的,如正則表達(dá)式等。切點(diǎn)是由一類連接點(diǎn)組成。

          Advice(通知):還是說(shuō)的通俗點(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í)行的代碼
          ??????* 返回通知是可以訪問(wèn)到目標(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í)行的代碼(無(wú)論目標(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í)行的代碼
          ??????* 可以訪問(wèn)到異常對(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()方法來(lái)執(zhí)行切入點(diǎn)方法,來(lái)作為環(huán)繞通知前后方法的分水嶺。
          ??????*
          ?????* 環(huán)繞通知類似于動(dòng)態(tài)代理的全過(guò)程: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)繞通知開(kāi)始=========");
          ?????????// 調(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"?>
          <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: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.xsd
          ????http://www.springframework.org/schema/tx
          ????http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
          ????http://www.springframework.org/schema/aop
          ????http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
          >

          ????
          ????
          ????<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


          采用注解來(lái)做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í)行通過(guò)之后執(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í)行的通知(無(wú)論目標(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)繞通知開(kāi)始=========");
          ????????// 調(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"?>
          <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: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.xsd
          ????http://www.springframework.org/schema/tx
          ????http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
          ????http://www.springframework.org/schema/aop
          ????http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
          >

          ????
          ????
          ????<aop:aspectj-autoproxy/>????
          ????
          ????
          ????<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.如果位于元素中,則命名切點(diǎn)只能被當(dāng)前內(nèi)定義的元素訪問(wèn)到,為了能被整個(gè)元素中定義的所有增強(qiáng)訪問(wèn),則必須在下定義切點(diǎn)。

          2.如果在元素下直接定義,必須保證之前定義。下還可以定義,三者在中的配置有先后順序的要求:首先必須是,然后是,最后是。而在中定義的則沒(méi)有先后順序的要求,可以在任何位置定義。


          .:用來(lái)定義切入點(diǎn),該切入點(diǎn)可以重用;
          .:用來(lái)定義只有一個(gè)通知和一個(gè)切入點(diǎn)的切面;
          .:用來(lái)定義切面,該切面可以包含多個(gè)切入點(diǎn)和通知,而且標(biāo)簽內(nèi)部的通知和切入點(diǎn)定義是無(wú)序的;和advisor的區(qū)別就在此,advisor只包含一個(gè)通知和一個(gè)切入點(diǎn)。

          3.在使用spring框架配置AOP的時(shí)候,不管是通過(guò)XML配置文件還是注解的方式都需要定義pointcut"切入點(diǎn)"


          例如定義切入點(diǎn)表達(dá)式 execution(* com.sample.service.impl..*.*(..))


          execution()是最常用的切點(diǎn)函數(shù),其語(yǔ)法如下所示:


          整個(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ù)。



          原文鏈接:cnblogs.com/xiaoxi/p/5981514.html



          瀏覽 44
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品久久久久久久久免费挑花 | 无码人妻丰满熟妇精品区 | 视频黄色国产 | 欧美成人性爱无码视频 | 青娱乐网址 |