Spring AOP

 
一。建立切面:
Spring中的通知類型有四種:
Around:攔截對目標對象方法調用,
Before:在目標方法被調用以前調用,
After:在目標方法被調用以後調用,
Throws:當目標方法拋出異常時調用。
1)下面是一個Before類型的簡單例子。
1.首先建立一個攔截的類:
package cn.itcast;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodBeforeAdvice;
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {//實現MethodBeforeAdvice接口
 Log log = LogFactory.getLog(this.getClass());
 public MyMethodBeforeAdvice() {
  super();
 }
 public void before(Method arg0, Object[] arg1, Object arg2)//實現MethodBeforeAdvice接口的before方法,
   throws Throwable {
  StringBuilder sb = new StringBuilder();
  if (arg1 == null) {
   sb = new StringBuilder("無參數!");
  } else {
   for (int i = 0; i < arg1.length; i++) {
    if (i != arg1.length - 1) {
     sb.append(arg1[i] + ",");
    } else {
     sb.append(arg1[i]);
    }
   }
  }
  log.info("類名: " + arg2.getClass().getName() + "   方法名: "
    + arg0.getName() + "   參數:" + sb.toString());
 }
}
這個類中咱們沒作太多的事,就是把方法名等信息打印出來而已,固然你能夠根據業務需求作其餘的不少事情。
2.
寫一個配置文件:applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" " [url]http://www.springframework.org/dtd/spring-beans.dtd[/url]">
<beans>
 <bean id="myArrayList" class="java.util.ArrayList" />
 <bean id="myMethodBeforeAdvice" class="cn.itcast.MyMethodBeforeAdvice" />
 <bean id="collection" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="interceptorNames">
   <!--指定攔截類的名字,能夠加入多個,它會去檢查此類實現的是什麼接口,而後去調用裏面相應的方法-->
   <list>
    <value>myMethodBeforeAdvice</value>
   </list>
  </property>
  <property name="target"><!--指定目標對象-->
   <ref bean="myArrayList" />
  </property>
  <property name="proxyInterfaces">
   <!--指定目標對象實現的接口,也能夠是多個-->
   <list>
    <value>java.util.Collection</value>
   </list>
  </property>
 </bean>
</beans>
3.再寫一個測試類
package cn.itcast.test;
import java.util.Collection;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMySpringAop extends TestCase {
 ApplicationContext applicationContext = null;
 Collection collection = null;
 protected void setUp() throws Exception {
  super.setUp();
  applicationContext = new ClassPathXmlApplicationContext(
    "applicationContext.xml");
 }
 public void testMySpring() {
  collection = (Collection) applicationContext.getBean("collection");
  collection.add("zhangsan");
  assertEquals(1, collection.size());
 }
}
運行!結果爲:
類名: java.util.ArrayList   方法名: add   參數:zhangsan
類名: java.util.ArrayList   方法名: size   參數:無參數!
看....簡單吧?!
2) 再來一個After的例子。
1.首先建立一個攔截的類:
package cn.itcast;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AfterReturningAdvice;
public class MyAfterReturningAdvice implements AfterReturningAdvice {
 Log log = LogFactory.getLog(this.getClass());
 public MyAfterReturningAdvice() {
  super();
 }
 public void afterReturning(Object arg0, Method arg1, Object[] arg2,
   Object arg3) throws Throwable {
  StringBuilder sb = new StringBuilder();
  if (arg2 == null) {
   sb = new StringBuilder("無參數!");
  } else {
   for (int i = 0; i < arg2.length; i++) {
    if (i != arg2.length - 1) {
     sb.append(arg2[i] + ",");
    } else {
     sb.append(arg2[i]);
    }
   }
  }
  log.info("返回值: " + arg0.toString() + "    類名: "
    + arg3.getClass().getName() + "   方法名: " + arg1.getName()
    + "   參數:" + sb.toString());
 }
}
2.把上面的XMl文件稍加改動便可,意思和上面的差很少,這裏就很少加註釋了。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" " [url]http://www.springframework.org/dtd/spring-beans.dtd[/url]">
<beans>
 <bean id="myArrayList" class="java.util.ArrayList" />
 <bean id="myAfterReturningAdvice" class="cn.itcast.MyAfterReturningAdvice" />
 <bean id="collection" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="interceptorNames">
   <value>myAfterReturningAdvice</value>
  </property>
  <property name="target">
   <ref bean="myArrayList" />
  </property>
  <property name="proxyInterfaces">
   <value>java.util.Collection</value>
  </property>
 </bean>
</beans>
3.測試類依然用上面那個。
運行!結果爲:
返回值的類型: true    類名: java.util.ArrayList   方法名: add   參數:zhangsan
返回值的類型: 1    類名: java.util.ArrayList   方法名: size   參數:無參數!
看......如今返回值也取出來了......... 
3) 再來看一個Around的例子。步驟和上面同樣,
1.首先也是建立一個攔截的類:
package cn.itcast;
import java.lang.reflect.Method;
import java.util.ArrayList;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MyMethodInterceptor implements MethodInterceptor {
 public MyMethodInterceptor() {
  super();
 }
 Log log = LogFactory.getLog(this.getClass());
 public Object invoke(MethodInvocation arg0) throws Throwable {
  Object[] arguments = arg0.getArguments();
  Method method = arg0.getMethod();
  Object objName = arg0.getThis();
  StringBuilder sb = new StringBuilder();
  if (arguments == null) {
   sb = new StringBuilder("無參數!");
  } else {
   for (int i = 0; i < arguments.length; i++) {
    if (i != arguments.length - 1) {
     sb.append(arguments[i] + ",");
    } else {
     sb.append(arguments[i]);
    }
   }
  }
  //在調用目標方法以前作的事
  log.info("類名: " + objName.getClass().getName() + "   方法名: " + method.getName()
    + "   參數:" + sb.toString());
  
  Object object = arg0.proceed();//經過調用此方法來調用目標方法。
  
  //在調用目標方法以後作的事
  if(objName instanceof ArrayList){
   ArrayList arrayList = (ArrayList) objName;
   arrayList.add("lisi");
   arrayList.add("wangwu");
   log.info("size = " + arrayList.size());
  }
  return object;
 }
}
2.把上面的XMl文件稍加改動便可,意思和上面的差很少,這裏就很少加註釋了。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" " [url]http://www.springframework.org/dtd/spring-beans.dtd[/url]">
<beans>
 <bean id="myArrayList" class="java.util.ArrayList" />
 <bean id="myMethodInterceptor" class="cn.itcast.MyMethodInterceptor" />
 <bean id="collection" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="interceptorNames">
   <value>myMethodInterceptor</value>
  </property>
  <property name="target">
   <ref bean="myArrayList" />
  </property>
  <property name="proxyInterfaces">
   <value>java.util.Collection</value>
  </property>
 </bean>
</beans>
3.運行!結果:
類名: java.util.ArrayList   方法名: add   參數:zhangsan
size = 3
類名: java.util.ArrayList   方法名: size   參數:無參數!
size = 5
咱們類分析一下運行的結果。在測試類中調用了一次目標類的add方法,此時size爲1,而後在攔截類裏面把對象取出來調用了兩次add方法,這時size爲3,也就是咱們看到的第一個size,接着在測試類中調用了一次size方法,此時它又被攔截了,因此再一次調用了兩個add方法,最後的size固然就是5了。固然若是咱們這裏用的是Set集合就不會再add後面的兩個已存在的對象了。
4)一個ThrowsAdvice的例子。步驟和上面同樣,
1.寫一個攔截異常的類。這裏面能夠有多個帶不一樣異常參數類型afterThrowing方法,運行時根據拋出異常的類型去調用恰當的方法,
package cn.itcast;
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
public class MyThrowsAdvice implements ThrowsAdvice {
 public MyThrowsAdvice() {
  super();
  // TODO Auto-generated constructor stub
 }
 public void afterThrowing(Method method, Object[] args, Object target,
   NullPointerException npe) {
  System.out.println("調用 " + target.getClass().getName() + " 的 "
    + method.getName() + " 方法時發生了 " + npe.getClass().getName()
    + " 異常!");
 }
}

2.xml文件。把上面的稍加修改:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" " [url]http://www.springframework.org/dtd/spring-beans.dtd[/url]">
<beans>
 <bean id="myArrayList" class="java.util.ArrayList" />
 <bean id="myMethodBeforeAdvice" class="cn.itcast.MyMethodBeforeAdvice" />
 <bean id="myAfterReturningAdvice" class="cn.itcast.MyAfterReturningAdvice" />
 <bean id="myMethodInterceptor" class="cn.itcast.MyMethodInterceptor" />
 <bean id="myThrowsAdvice" class="cn.itcast.MyThrowsAdvice" />
 <bean id="collection" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="interceptorNames">
   <value>myThrowsAdvice</value>
  </property>
  <property name="target">
   <ref bean="myArrayList" />
  </property>
  <property name="proxyInterfaces">
   <value>java.util.Collection</value>
  </property>
 </bean>
</beans>
3.寫一個main方法來測試一下:
package cn.itcast;
import java.util.Collection;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {
 public MainClass() {
  super();
 }
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  ApplicationContext applicationContext = null;
  Collection collection = null;
  applicationContext = new ClassPathXmlApplicationContext(
    "applicationContext.xml");
  collection = (Collection) applicationContext.getBean("collection");
  collection.add("zhangsan");
  Object[] object = null;
  collection.toArray(object);//故意來拋出一個異常試試看
 }
}

來看看運行結果:
調用 java.util.ArrayList 的 toArray 方法時發生了 java.lang.NullPointerException 異常!
Exception in thread "main" java.lang.NullPointerException
 at java.util.ArrayList.toArray(Unknown Source)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 at java.lang.reflect.Method.invoke(Unknown Source)
 at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:335)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:181)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:148)
 at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:118)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
 at $Proxy0.toArray(Unknown Source)
 at cn.itcast.MainClass.main(MainClass.java:29)
看到了嗎?咱們在攔截異常類裏面的打印語句出來了:
調用 java.util.ArrayList 的 toArray 方法時發生了 java.lang.NullPointerException 異常!
固然在這裏你還能夠作不少事情。在本程序裏面僅打印出這條簡單的信息而已。 下面的是系統拋出的。由此能夠看出,若是有異常的話,代理對象捕獲異常而且調用合適的ThrowsAdvice方法。ThrowsAdvice被執行後,原來的異常繼續被拋出,而且象其餘異常同樣被傳播出去。  
相關文章
相關標籤/搜索