天天看點

spring的AOP元件

spring的AOP元件是基于這樣一種思想:讓程式員把分散在代碼中的重複功能提取出來,單獨編寫成一個類(spring叫通知advice),通過動态代理的手段再加入到需要它的地方。

1>.spring要求advice要按照它的要求進行編寫。它給提供了四個接口可供使用,以便在目标方法執行的不同時期不同情況下,能夠觸發執行advice裡的方法:

    MethodBeforeAdvice:在目标方法調用之前觸發執行它的方法before(...);

   AfterReturningAdvice:在目标方法傳回值之前觸發執行它的方法afterReturning(...);

   MethodInterceptor:      可以在它的方法invoke(...)執行過程中調用目标方法;

   ThrowsAdvice:             在目标方法發生異常時觸發執行它實作類裡面的方法afterThrowing(...)。

2>.spring通過類org.springframework.aop.framework.ProxyFactoryBean來實作把advice和目标類結合起來完成動态代理功能,向使用者提供所需要的代理類。

目标類實作的接口:

public interface StudentDao { 

  public void test1(); 

  public void test2() throws Exception; 

}

目标類:

public class StudentDaoImpl implements StudentDao { 

  public void test1() { 

    try { 

      Thread.sleep(2000);//用來使測試時間更加明顯 

    } catch (InterruptedException e) { 

      e.printStackTrace(); 

    } 

    System.out.println("@@@@執行目标方法:test1()@@@@"); 

  } 

  public void test2() throws Exception { 

    System.out.println("####執行目标方法:test2()####"); 

    throw new SQLException("test2 has SQLException"); 

Advice:

public class SecurityAdvice implements MethodBeforeAdvice { 

  /*    

    * method: 目标方法 

    * args: 目标方法的參數清單 

    * target: 目标對象 

    */ 

  @Override 

  public void before(Method method, Object[] args, Object target) 

      throws Throwable { 

    System.out.println("====security check for: "+method.getName()+" ===="); 

public class LoggingAdvice implements AfterReturningAdvice { 

    * returnValue: 目标方法的傳回值 

  public void afterReturning(Object returnValue, Method method, Object[] args, 

      Object target) throws Throwable { 

    System.out.println("****"+method.getName()+" run at "+new Date()+" ****"); 

public class PerformanceAdvice implements MethodInterceptor { 

  /** 

    * invocation: 是對目标方法的一個封裝,不但包含了目标方法本身以及它的參數清單,還包括目标對象. 

  public Object invoke(MethodInvocation invocation) throws Throwable { 

    Long beginTime=System.currentTimeMillis(); 

    Object ret=invocation.proceed();//對外提供了此方法,用來執行目标方法. 

    Long endTime=System.currentTimeMillis(); 

    System.out.println("####"+invocation.getMethod().getName()+" used "+(endTime-beginTime)+" ms####"); 

    return ret; 

public class MyThrowsAdvice implements ThrowsAdvice { 

    * ThrowsAdvice接口本身并不包含任何方法,但spring要求它裡面要觸發的方法必須叫afterThrowing,并且允許程式員無限重載之。其實這也是不得已的做法,因為spring不可能事先定義好目标方法要發生的所有異常情況,交給程式員自行處理也許是個最好的選擇。

    *需要特别指出的是:當異常發生重疊時,它采用的是最精确比對執行。

    * @param e: 目标方法抛出的異常對象 

  public void afterThrowing(Exception e) {// 目标方法發生Exception時執行本方法 

    System.out.println("@@@@catch Exception " + e.getMessage() + "@@@@"); 

  public void afterThrowing(RuntimeException e) {// 目标方法發生RuntimeException時執行本方法 

    System.out.println("@@@@catch RuntimeException " + e.getMessage()+ "@@@@"); 

  public void afterThrowing(SQLException e) {// 目标方法發生SQLException時執行本方法 

    System.out.println("@@@@catch SQLException " + e.getMessage() + "@@@@"); 

  public void afterThrowing(IOException e) {// 目标方法發生IOException時執行本方法 

    System.out.println("@@@@catch IOException " + e.getMessage() + "@@@@"); 

配置檔案:

<beans> 

  <bean id="target" class="com.yangfei.spring.advice.StudentDaoImpl"> 

  </bean> 

  <bean id="before" class="com.yangfei.spring.advice.SecurityAdvice"></bean> 

  <bean id="after" class="com.yangfei.spring.advice.LoggingAdvice"></bean> 

  <bean id="interceptor" class="com.yangfei.spring.advice.PerformanceAdvice"></bean> 

  <bean id="throws" class="com.yangfei.spring.advice.MyThrowsAdvice"></bean> 

  <bean id="dao" class="org.springframework.aop.framework.ProxyFactoryBean"> 

    <property name="target"><!-- 目标類 --> 

      <ref bean="target"/> 

    </property> 

    <property name="interceptorNames"><!-- Adivice --> 

      <list> 

        <value>before</value> 

        <value>after</value> 

        <value>interceptor</value> 

        <value>throws</value> 

      </list> 

    <property name="interfaces"><!-- 目标類實作的接口 --> 

        <value>com.yangfei.spring.advice.StudentDao</value> 

</beans>

測試類:

  public static void main(String[] args) throws Exception{ 

    ApplicationContext ctx=new ClassPathXmlApplicationContext("test.xml"); 

    StudentDao dao=(StudentDao)ctx.getBean("dao"); 

    dao.test1(); 

    System.out.println(); 

    dao.test2(); 

  }

運作結果:

====security check for: test1 ====

@@@@執行目标方法:test1()@@@@

####test1 used 2000 ms####

****test1 run at Sat Dec 19 10:04:28 CST 2009 ****

====security check for: test2 ====

####執行目标方法:test2()####

@@@@catch SQLException test2 has SQLException@@@@

Exception in thread "main" java.sql.SQLException: test2 has SQLException

 at com.cernet.spring.advice.StudentDaoImpl.test2(StudentDaoImpl.java:30)

.......

     本文轉自NightWolves 51CTO部落格,原文連結:http://blog.51cto.com/yangfei520/245613,如需轉載請自行聯系原作者