Spring中创建切面

来源:互联网 发布:小青柑淘宝店导航条 编辑:程序博客网 时间:2024/04/30 16:58


一。创建切面:
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" "http://www.springframework.org/dtd/spring-beans.dtd">

<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" "http://www.springframework.org/dtd/spring-beans.dtd">

<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" "http://www.springframework.org/dtd/spring-beans.dtd">

<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" "http://www.springframework.org/dtd/spring-beans.dtd">

<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被执行后,原来的异常继续被抛出,并且象其他异常一样被传播出去。
 

原创粉丝点击