spring學習(二)—通知

通知類型

1、Spring只支持方法通知,也就是說,只能在方法的前後進行通知,而不能在屬性前後進行通知。
2、Spring支持四種通知類型:目標方法調用前(before),目標方法調用後(after),目標方法調用前後(around),以及目標方法拋出異常(throw)。
3、前置通知的類必須實現MethodBeforeAdvice接口,實現其中的before方法。
4、後置通知的類必須實現AfterReturningAdvice接口,實現其中的afterReturning方法。
5、環繞通知的類必須實現MethodInterceptor接口,實現其中的invoke方法。前後通知是唯一可以控制目標方法是否被真正調用的攔截類型,也可以控制返回對象。而前置攔截或後置攔截不能控制,它們不能印象目標方法的調用和返回。
6、異常通知 要實現 ThrowsAdvice ,ThrowAdvice 接口只是一個標示接口,它沒有任何的方法,但是在使用時我們需要實現afterThrowing 方法來實現通知的具體內容。

測試

前置通知

ProBeginAdvice.java

package com.lgh.spring.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class ProBeginAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        System.out.println("前置通知:開啓事務");

    }

}

後置通知

ProAfterAdvice

package com.lgh.spring.advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class ProAfterAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
       System.out.println("後置通知:提交事務");
    }



}

異常通知

ExecpetionAdvice.java

package com.lgh.spring.advice;

import java.lang.reflect.Method;

import org.springframework.aop.ThrowsAdvice;

public class ExecpetionAdvice implements ThrowsAdvice {

    public void afterThrowing(Method m,Object[] os,Object target,Exception throwable)  
    {  
        System.out.println("異常通知: 程序出問題了:" + throwable.getMessage());  
    }  
}

環繞通知

AroundInterceptor

package com.lgh.spring.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/*
 * 環繞通知
 * */
public class AroundInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {

         System.out.println("環繞通知被調用:調用方法前執行  ");  
            Object obj = arg0.proceed();  
            System.out.println("環繞通知被調用:調用方法後執行   ");  
        return obj;
    }


}
被代理的類
ProductDaoImpl

package com.lgh.spring.dao.impl;

public class ProductDaoImpl {

public void save(){
    System.out.println("保存商品");
}

public void del(){

    System.out.println("刪除商品");
    //int i = 9/0;
}

}

在applicationContext.xml中配置

<bean id="productDao" class="com.lgh.spring.dao.impl.ProductDaoImpl" lazy-init="true"></bean>
<!-- 配置前置通知 -->  
<bean id="proBegin" class="com.lgh.spring.advice.ProBeginAdvice" lazy-init="true"></bean>
<!-- 配置後置通知 -->  
<bean id="proAfter" class="com.lgh.spring.advice.ProAfterAdvice" lazy-init="true"></bean>
<!-- 配置異常通知 -->  
<bean id="proThrow" class="com.lgh.spring.advice.ExecpetionAdvice"></bean>
<!-- 配置環繞通知 --> 
<bean id="proAround" class="com.lgh.spring.advice.AroundInterceptor"></bean> 
<!-- 配置代理對象 -->  
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean" >
<!-- 代理目標 -->
<property name="target" ref="productDao"></property>
<!-- 代理時所使用的通知   攔截器名集-->
<property name="interceptorNames">
<list>
<!-- 相當於把 MyMethodBeforeAdvice前置通知和代理對象關聯起來,
         我們也可以把通知看成攔截器,struts2核心就是攔截器 -->  
<value>proBegin</value>
<value>proAfter</value>
<value>proThrow</value>
<value>proAround</value>
</list>
</property>

測試

SpringTest02

package com.lgh.spring.test;

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

import com.lgh.spring.biz.UserBiz;
import com.lgh.spring.dao.impl.ProductDaoImpl;

public class SpringTest02 {

   public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    /*
     * 通過代理獲取ProductDaoImpl
     * 因爲ProductDaoImpl本身並沒有與通知類有聯繫
     * 
     * */
    ProductDaoImpl productDao = (ProductDaoImpl) ac.getBean("proxy");

    System.out.println(productDao.getClass());
    productDao.save();
    System.out.println("------------------");
    productDao.del();
   }

}

結果:

class com.lgh.spring.dao.impl.ProductDaoImpl$$EnhancerBySpringCGLIB$$e5e8be14
前置通知:開啓事務
環繞通知被調用:調用方法前執行  
保存商品
環繞通知被調用:調用方法後執行   
後置通知:提交事務
前置通知:開啓事務
環繞通知被調用:調用方法前執行  
刪除商品
環繞通知被調用:調用方法後執行   
後置通知:提交事務

我們在ProductDaoImpl的del方法中添加一個除零異常

public void del(){

        System.out.println("刪除商品");
        int i = 9/0;
    }

運行結果:

class com.lgh.spring.dao.impl.ProductDaoImpl$$EnhancerBySpringCGLIB$$e5e8be14
前置通知:開啓事務
環繞通知被調用:調用方法前執行  
保存商品
環繞通知被調用:調用方法後執行   
後置通知:提交事務
------------------
前置通知:開啓事務
環繞通知被調用:調用方法前執行  
刪除商品
異常通知: 程序出問題了:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.lgh.spring.dao.impl.ProductDaoImpl.del(ProductDaoImpl.java:12)
    at com.lgh.spring.dao.impl.ProductDaoImpl$$FastClassBySpringCGLIB$$c7e39ca2.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    ...

我們看到配置的異常通知起作用了

自動代理bean 定義

這時,我們所配置的代理只對一個對象起作用,如果有多個對象時,使用起來比較麻煩,
我們在這裏可以使用自動代理bean 定義

<!-- 自動代理bean 定義 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<!-- 配置需要使用代理的bean -->
<value>pro*,userDao</value>
</property>
<property name="interceptorNames">
<list>
<value>proBegin</value>
<value>proAfter</value>
<value>proThrow</value>
<value>proAround</value>
</list>
</property>
</bean>
<bean id="userDao" class="com.lgh.spring.dao.impl.UserDaoMysqlImpl" lazy-init="true" >
</bean>
<bean id="userBiz" class="com.lgh.spring.biz.impl.UserBizImpl" lazy-init="true">
<property name="userDao" ref="userDao"></property>
</bean>

測試

package com.lgh.spring.test;

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

import com.lgh.spring.biz.UserBiz;
import com.lgh.spring.dao.impl.ProductDaoImpl;

public class SpringTest03 {

   public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    ProductDaoImpl productDao = (ProductDaoImpl) ac.getBean("productDao");


    productDao.save();
    System.out.println("----------------------------------");
    UserBiz ub = (UserBiz) ac.getBean("userBiz");
    ub.save();
    System.out.println("----------------------------------");
    productDao.del();
   }

}

結果:

前置通知:開啓事務
環繞通知被調用:調用方法前執行  
保存商品
環繞通知被調用:調用方法後執行   
後置通知:提交事務
----------------------------------
UserDaoMysqlImpl 構造方法
前置通知:開啓事務
環繞通知被調用:調用方法前執行  
UserDaoMysqlImpl save方法
環繞通知被調用:調用方法後執行   
後置通知:提交事務
----------------------------------
前置通知:開啓事務
環繞通知被調用:調用方法前執行  
刪除商品
異常通知: 程序出問題了:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.lgh.spring.dao.impl.ProductDaoImpl.del(ProductDaoImpl.java:12)
    at com.lgh.spring.dao.impl.ProductDaoImpl$$FastClassBySpringCGLIB$$c7e39ca2.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章