`
senton
  • 浏览: 201088 次
  • 性别: Icon_minigender_1
  • 来自: 紫禁城
社区版块
存档分类
最新评论

Spring中创建切面

阅读更多


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

分享到:
评论

相关推荐

    Spring AOP 建立一个简单的切面及测试

    实现一个简单的spring aop切面,并对切点以及切面操作进行测试,内附代码和截图

    Spring Boot Aspect 切面 AOP 拦截器 Interceptor 监控control请求耗时

    常用拦截 拦截器HandlerInterceptor 拦截器MethodInterceptor 添加依赖 创建启动类 创建拦截器类 创建控制器 监控control请求耗时,提高性能

    SpringAOP切面实例讲解及应用场景(通俗易懂)

    下面是一个在spring mvc中关于切面如何使用的例子,可以指直观的理解切面到底有什么作用 1、引用 AspectJ jar 包依赖 pom.xml 文件添加依赖 org.aspectj aspectjrt 1.9.2 2、创建两个新的包 ...

    spring aop 切面添加日志

    此工程为使用eclipse创建java project,使用jdk1.8,项目中包含完整的代码和jar包,导入eclipse即可运行

    Spring 中文API&开发文档.rar

    ◆面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑...

    Spring-Reference_zh_CN(Spring中文参考手册)

    6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API ...

    Spring中文帮助文档

    6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API ...

    spring课堂笔记的相关知识

    Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能 声明式事务的支持 只需要通过配置就可以完成对事务的管理,而无需手动编程 方便程序的测试 Spring对Junit4支持,可以通过注解方便的...

    黑马程序员spring2016springday01上课笔记

    (1)aop:面向切面编程,扩展功能不是修改源代码实现 (2)ioc:控制反转, - 比如有一个类,在类里面有方法(不是静态的方法),调用类里面的方法,创建类的对象,使用对象调用方法,创建类对象的过程,需要new...

    spring3.0jar包

    ◆面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑...

    史上最全 69 道 Spring 面试题和答案

    • 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开 • 容器:Spring 包含并管理应用中对象的生命周期和配置 • MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很...

    spring4示例代码

    spring-3 演示使用动态代理模式实现面向切面编程 使用注解方式进行AOP编程及使用配置xml方式进行AOP编程 spring-4 演示了spring与JDBCTemplate配合使用 spring-5 演示了声明式事务及使用xml配置文件处理事务

    Spring详细学习资料下载

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. spring的设计思想是,单例模式和工厂模式 2 spring的四大特点(优点) 轻量级,低侵入的设计 Spring的DI机制降低了业务对象替换的复杂性 spring不...

    Spring 2.0.8 API帮助文档

    Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由... 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

    Spring导入包.zip

    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod ...Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架

    spring-framework-3.1.0.RELEASE.zip

    面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——...

    spring4.1核心包

    Spring面向切面编程,提供AOP实现。Spring Beans之上将横切关注点模块化 2. spring-aspects-4.1.1.RELEASE.jar 提供的对AspectJ框架的整合,也是A面向切面编程。 AspectJ可用于基于普通Java对象的模块化 注意:...

    spring.docx

    • Spring是一个开源框架,是为了解决企业应用开发的复杂性而创建的。 Spring在软件开发中所占的位置是承上启下。...• 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

    JAVA中spring介绍及心得.docx

    Spring框架的核心特点包括依赖注入(Dependency Injection)、面向切面编程(Aspect-Oriented Programming)、事务管理、模型-视图-控制器(Model-View-Controller,MVC)等。下面我会介绍一些关于Spring框架的核心...

    Spring Aop + 海绵宝宝 你的了解是

    面向切面编程(Aspect-Oriented Programming,AOP):Spring支持面向切面编程,允许开发者将横切关注点(如日志、事务、安全性等)从核心业务逻辑中分离出来,并以模块化的方式进行重用。这样可以提高代码的可维护性...

Global site tag (gtag.js) - Google Analytics