基於配置的Spring AOP


前面幾篇學習了Spring的依賴注入,這篇開始學習另一個核心功能——面向切面編程AOP

  通過本文,你可以了解到:

  1 Spring xml規范

  2 通過配置文件實現面向切面編程

  3 對比與傳統AOP編程

Spring的xml文件

  Spring的xml一般起名叫做bean.xml或者xxxapplication.xml這種,然后放在src下通過ClassPathXmlApplicationContext進行加載。文件的內容如下:

<?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:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> 
    
    <bean id="audience"class="com.spring.test.aop.Audience"/>

    <aop:config>
    </aop:config>
</beans>

  最上面的是xml的編碼,這個就不解釋了。

  下面的<beans>是Spring的配置標簽,beans里面幾個重要的屬性

  xmlns:

  是默認的xml文檔解析格式,即spring的beans。地址是http://www.springframework.org/schema/beans。

  通過設置這個屬性,所有在beans里面聲明的屬性,可以直接通過<>來使用,比如<bean>等等。

  xmlns:xsi:

  是xml需要遵守的規范,通過URL可以看到,是w3的統一規范,后面通過xsi:schemaLocation來定位所有的解析文件。

  xmlns:aop:

  這個是重點,是我們這里需要使用到的一些語義規范,與面向切面AOP相關。

  xmlns:tx:

  Spring中與事務相關的配置內容。

  

  一個XML文件,只能聲明一個默認的語義解析的規范。

  例如上面的xml中就只有beans一個是默認的,其他的都需要通過特定的標簽來使用,比如aop,它自己有很多的屬性,如果要使用,前面就必須加上aop:xxx才可以。比如上面的aop:config。

  類似的,如果默認的xmlns配置的是aop相關的語義解析規范,那么在xml中就可以直接寫config這種標簽了。

 

基於配置的AOP編程過程

  首先,如果要在工程中使用AOP需要幾個jar包:

  1 Aop的核心包,即org.springframework.aop-xxx.jar

  2 Spring的聯盟包:aopalliance-1.0.jar

  3 aspectJ相關的jar包:aspectjrt.jar aspectjweaver.jar

  4 如果使用了動態代理,還需要添加cglib相關的jar包:cglib.zip

  首先需要一個AOP的切面類,用於定義各種響應事件

package com.spring.test.aop;

public class Audience {
    public void takeSeats(){
        System.out.println("The audience is taking their seats.");
    }
    public void turnOffCellPhones(){
        System.out.println("The audience is turning off their cellphones");
    }
    public void applaud(){
        System.out.println("CLAP CLAP CLAP");
    }
    public void demandRefund(){
        System.out.println("Boo! We want money back");
    }
}

  然后在bean.xml中編寫aop:config的相關內容:

...省略beans的定義內容

    <bean id="audience" class="com.spring.test.aop.Audience"/>
    
    <bean id="sax" class="com.spring.test.setter.Saxophone"/>
    <bean id="kenny" class="com.spring.test.setter.Instrumentalist">
         <property name="song" value="Jingle Bells" />
         <property name="age" value="25" />
         <property name="instrument" ref="sax"/>
    </bean>
    
    <aop:config proxy-target-class="true">
        <aop:aspect ref="audience">
            <aop:pointcut id="performance" expression="execution(* com.spring.test.action1.Performer.perform(..))"/>
            
            <aop:before pointcut-ref="performance" method="takeSeats"/>
            <aop:before pointcut-ref="performance" method="turnOffCellPhones"/>
            <aop:after-returning pointcut-ref="performance" method="applaud"/>
            <aop:after-throwing pointcut-ref="performance" method="demandRefund"/>
        </aop:aspect>
    </aop:config>
</beans>

  這里面的aop:pointcut 就是使用AspectJ來定位的。意思是:當執行com.spring.test.action1.Performer的perform方法時,就會觸發該切面的事件響應。

  而Performer以及Instrumentalist等等的代碼,就在下面簡單的都羅列出來了:

  配置文件bean.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:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> 
    
    <bean id="audience" class="com.spring.test.aop.Audience"/>
    
    <bean id="sax" class="com.spring.test.setter.Saxophone"/>
    <bean id="kenny" class="com.spring.test.setter.Instrumentalist">
         <property name="song" value="Jingle Bells" />
         <property name="age" value="25" />
         <property name="instrument" ref="sax"/>
    </bean>
    
    <aop:config proxy-target-class="true">
        <aop:aspect ref="audience">
            <aop:pointcut id="performance" expression="execution(* com.spring.test.action1.Performer.perform(..))"/>
            
            <aop:before pointcut-ref="performance" method="takeSeats"/>
            <aop:before pointcut-ref="performance" method="turnOffCellPhones"/>
            <aop:after-returning pointcut-ref="performance" method="applaud"/>
            <aop:after-throwing pointcut-ref="performance" method="demandRefund"/>
        </aop:aspect>
    </aop:config>
</beans>
View Code

  表演者接口Performer.java

package com.spring.test.action1;

public interface Performer {
    void perform() throws PerformanceException;
}
View Code

  表演者實現類Instrumentalist.java

package com.spring.test.setter;

import com.spring.test.action1.PerformanceException;
import com.spring.test.action1.Performer;

public class Instrumentalist implements Performer{
    private String song;
    private int age;
    private Instrument instrument;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSong() {
        return song;
    }
    public void setSong(String song) {
        this.song = song;
    }
    public Instrument getInstrument() {
        return instrument;
    }
    public void setInstrument(Instrument instrument) {
        this.instrument = instrument;
    }
    public Instrumentalist(){}
    public Instrumentalist(String song,int age,Instrument instrument){
        this.song = song;
        this.age = age;
        this.instrument = instrument;
    }
    public void perform() throws PerformanceException {
        System.out.println("Instrumentalist age:"+age);
        System.out.print("Playing "+song+":");
        instrument.play();
    }
}
View Code

  內部bean接口Instrument.java

package com.spring.test.setter;

public interface Instrument {
    public void play();
}
View Code

  內部bean實現類Saxophone.java

package com.spring.test.setter;

public class Saxophone implements Instrument {
    public Saxophone(){}
    public void play() {
        System.out.println("TOOT TOOT TOOT");
    }
}
View Code

  測試主函數main

package com.spring.test.setter;

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

import com.spring.test.action1.PerformanceException;

public class test {
    public static void main(String[] args) throws PerformanceException {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
        
        Instrumentalist performer = (Instrumentalist)ctx.getBean("kenny");
        performer.perform();
        
    }
}
View Code

  運行結果:

The audience is taking their seats.
The audience is turning off their cellphones
Instrumentalist age:25
Playing Jingle Bells:TOOT TOOT TOOT
CLAP CLAP CLAP

 

  通過這種聲明方式,可以 快速的實現切點與切面的整合,成為下面這種格式的新代碼:

class{
  try{  
  audience.takeSeats();    
  audience.turnOffCellphones();

  performance.perform();  

  audience.applaud();  
  }catch(Exception){
    audience.demandRefund();
  }   
}

  面向切面的好處,要在實際工作中多加領會才可以,常用的場景就是日志的記錄了。

 

與傳統的AOP編程相比

  前面也做過一個傳統的spring aop的實現方法:http://www.cnblogs.com/xing901022/p/4143696.html

  不得不說,通過ProxyFactoryBean達到的面向切面的編程,過於復雜,光是那幾個功能就要好好理解一番。

  而基於配置的AOP使用就要簡單的多,只需要一個切面的程序,然后通過配置文件就可以完全解耦的融入到切點中。


免責聲明!

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



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