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,如需轉載請自行聯系原作者