1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 7673字,需瀏覽 16分鐘

         ·

        2020-09-11 05:13


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


        采用注解來做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"?>
        <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)定義的元素訪問到,為了能被整個(gè)元素中定義的所有增強(qiáng)訪問,則必須在下定義切點(diǎn)。

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


        .:用來定義切入點(diǎn),該切入點(diǎn)可以重用;
        .:用來定義只有一個(gè)通知和一個(gè)切入點(diǎn)的切面;
        .:用來定義切面,該切面可以包含多個(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ù)。



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



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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            天天爽夜夜春 | 护士扒下内裤让我爽一夜电影 | 亚洲精品99久91在线传媒一区 | 麻豆成人免费视频在线观看 | 尹人网站 | 午夜视频在线瓜伦 | 《甜性涩爱》完整版在线播放 | 69久久久| 欧美性生活视频播放 | 男生和女生操的视频 |