Spring AOP(面向切面示例)


什么是AOP?
基本概念
切面(aspect):橫切關注點被模塊化的特殊對象。
通知(advice):切面必須要完成的工作。切面中的每個方向稱之為通知。通知是在切面對象中的。
目標(target):被通知的對象。
代理(proxy):向目標對象應用通知后創建的對象。

連接點(joinpoint):目標對象的程序執行的某個特定位置。如某個方法調用前,調用后的位置。包括兩個信息:1.目標程序的哪個方法?2.方法執行 
前還是執行后?
切點(pointcut):每個類會有多個連接點,AOP通過切點定位到特定的邊接點。
類比,連接點相當於數所成方圓 中的記錄,而切點相當於查詢條件。一個切點匹配多個連接點。

使用XML配置的方法:

1.導入 spring包和aspectj的兩個jar包

2.目標對象(要切入的對象)

首先為了不違反開閉原則和更好的可擴展性,目標對象實際上是實現了已定義好的某個接口

接口:

package com.itnba.test;

public interface IHuman {
    public void chifan();
    public void shuijiao();

}

實現接口的兩個類:

package com.itnba.test;

import org.springframework.stereotype.Component;

public class Chinese implements IHuman {

    @Override
    public void chifan() {
        // TODO 自動生成的方法存根
        System.out.println("中國人吃飯");

    }
    
    @Override
    public void shuijiao() {
        // TODO 自動生成的方法存根
        System.out.println("中國人睡覺");
    }

}
package com.itnba.test;

import org.springframework.stereotype.Component;


public class American implements IHuman {

    @Override
    public void chifan() {
        // TODO 自動生成的方法存根
        System.out.println("美國人吃飯");

    }

    @Override
    public void shuijiao() {
        // TODO 自動生成的方法存根
        System.out.println("美國人睡覺");
    }


}

3.定義一個切面類

package com.itnba.test;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
public class Qiemian {
    
    public void chifanqian(){
        System.out.println("洗手");
    }
    public void chifanhou(){
        System.out.println("漱口");
    }
    public void shuijiaoqian(){
        System.out.println("洗澡");
        
    }

}

4.XML文件配置

<?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/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"
        default-autowire="byName"
        >
         <!-- 首相要實例化目標對象類和切面類 -->
        <bean id="chinese" class="com.itnba.test.Chinese"></bean>
        <bean id="american" class="com.itnba.test.American"></bean>
        <bean id="qiemian" class="com.itnba.test.Qiemian"></bean>
        
        <aop:config>
        <!-- 要切入的對象 -->                 
        <aop:pointcut expression="execution(* com.itnba.test.*.chifan(..))" id="chifan"/>
        <aop:pointcut expression="execution(* com.itnba.test.*.shijiao(..))" id="shijiao"/>
        <!-- 切入點 -->
        <aop:aspect id="ha" ref="qiemian"><!-- 切面類  -->
            <!--  <aop:之前before、之后after... method="切面類中的方法" pointcut-ref="上面的切入的對象"/>  -->
            <aop:before method="chifanqian()" pointcut-ref="chifan"/><!-- 之前通知 -->
            <aop:after method="chifanhou()()" pointcut-ref="chifan"/><!-- 之后通知 -->
            <aop:before method="shuijiaoqian()" pointcut-ref="shijiao"/>
        </aop:aspect>
    </aop:config>
</beans>

5.運行

package com.itnba.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //要用接口接收
        IHuman c= (IHuman)context.getBean("chinese");
        c.chifan();
        c.shuijiao();
        System.out.println("*********************************");
        //要用接口接收
        IHuman a= (IHuman) context.getBean("american");
        a.chifan();
        a.shuijiao();

    }

}

結果:

 

使用注解的方法:

1.導如 spring包和aspectj的兩個jar包

 


2.配置文件中加入aop命名空間

<?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/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd" >

        <!-- 自動掃描包下的類,並將其實例化。多個包之間用,隔開 -->
        <context:component-scan base-package="com.itnba.test"></context:component-scan>
        <!-- 配置文件中啟動AspectJ的注解功能 ,默認是false,要將其改為true -->
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> 
</beans>

3.目標對象(要切入的對象)

首先為了不違反開閉原則和更好的可擴展性,目標對象實際上是實現了已定義好的某個接口

接口:

package com.itnba.test;

public interface IHuman {
    public void chifan();
    public void shuijiao();

}

實現接口的兩個類:

package com.itnba.test;

import org.springframework.stereotype.Component;

@Component
public class Chinese implements IHuman {

    @Override
    public void chifan() {
        // TODO 自動生成的方法存根
        System.out.println("中國人吃飯");

    }
    
    @Override
    public void shuijiao() {
        // TODO 自動生成的方法存根
        System.out.println("中國人睡覺");
    }

}
package com.itnba.test;

import org.springframework.stereotype.Component;

@Component
public class American implements IHuman {

    @Override
    public void chifan() {
        // TODO 自動生成的方法存根
        System.out.println("美國人吃飯");

    }

    @Override
    public void shuijiao() {
        // TODO 自動生成的方法存根
        System.out.println("美國人睡覺");
    }


}

4.定義一個切面類,直接在里面注解

package com.itnba.test;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect //聲明該類是切面類
@Component//配置文件中啟動自動掃描功能
public class Qiemian {
    
    @Before("execution(* com.itnba.test.*.chifan(..))")//在那個方法的之前通知    *代表全部..代表所有形參,不管有多少
    public void chifanqian(){
        System.out.println("洗手");
    }
    @After("execution(* com.itnba.test.*.chifan(..))")//在那個方法之后通知
    public void chifanhou(){
        System.out.println("漱口");
    }
    @Before("execution(* com.itnba.test.*.shuijiao(..))")
    public void shuijiaoqian(){
        System.out.println("洗澡");
        
    }

}

5.寫好后用main函數來運行一下

package com.itnba.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Chinese c= context.getBean(Chinese.class);
        c.chifan();
        c.shuijiao();
        System.out.println("*********************************");
        American a= (American) context.getBean("american");
        a.chifan();
        a.shuijiao();

    }

}

結果:

這樣,Spring的面向切面編程就簡單介紹完了。

通知分類:
前置通知(@Before) -- 在目標方法執行前執行的通知。
后置通知(@After) -- 在目標方法執行后執行的通知。無論是否發生異常。后置通知中,無法讀取目標方法返回的結果。
返回通知(@AfterReturnning) --在目標方法執行成功后執行的通知。在返回通知中可以訪問目標返回結果的。 
@AfterReturnning(value="execution(* com.itnba..*(..))",returning="result")
public void afterRun(Object result){
System.out.println(result);
}

異常通知(@AfterThrowing) -- 在目標方法執行出錯后執行的通知。
@AfterThrowing(value="execution(* com.itnba..*(..))",throwing="ex")
public void afterThrowing(Exception ex){
System.out.println(ex.getMessage());
}

環繞通知(@Around) -- 需要切面方法攜帶ProceedingJoinPoion參數,類似於一個完整的動態代理,環繞通知必須要有一個返回值,是目標方法的返 
回值。

@Around("execution(* com.itnba..*(..))")
public object aroundAdvice( ProceedingJoinPoint pjp){

object obj = null;
try{
//做前置通知
obj = pjp.proceed();
//做返回通知
}
catch(Exception ex){
//做異常通知
}
//做后置通知
return obj;
}

 

添加日志:

切面方法可以加入參數(JoinPoint) joinPost.getSignature().getXXX()獲得相關方法信息
切面方法中可以加入Object參數,用來獲得目標方法的返回值(只對返回通知起作用)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM