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