spring笔记--使用springAPI以及自定义类 实现AOP的一个例子

  Spring的另一个重要思想是AOP,面向切面的编程,它提供了一种机制,可以在执行业务前后执行另外的代码,Servlet中的Filter就是一种AOP思想的体现,下面通过一个例子来感受一下.

  假设我们现在需要在针对数据库进行CRUD操作时添加一组日志,即在执行CRUD方法前后分别加上一句话,实现简单的面向切面编程的功能.我用到的是spring4,在配置文件上较之之前的版本可能有些不同.

  使用springAPI来实现AOP,除了spring必不可少的核心jar包,还需要两个jar包需要导入:

    1.   aspectjweaver.jar   下载链接: http://download.csdn.net/detail/luojiming1990/5432831
    2.   aopalliance.jar    下载链接:http://download.csdn.net/detail/zhaoshe/3153090

  并且配置文件的头文件也需要略作修改,需要加入aop的命名空间(namespace),详见下面实例中的beans.xml.

  UserService类(省略数据库操作代码,只做简单的打印来模拟):

复制代码

public class UserService {

    void add(){
        System.out.println("添加用户");
    }
     delete(){
        System.out.println("删除用户" update(){
        System.out.println("修改用户" search(){
        System.out.println("查询用户");
    }
}

复制代码

Log类(在执行增删改查方法前执行):

复制代码

class Log  implements MethodBeforeAdvice{

    /***
     * method:被调用的方法对象
     * arg1:被调用的方法的参数
     * target:被调用方法的目标对象 
     */
    @Override
     before(Method method,Object[] arg1,Object target)
            throws Throwable {
        System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被执行");
    }

}

复制代码

AfterLog类(在执行增删改查方法后执行):

复制代码

class AfterLog  AfterReturningAdvice{
    
     * returnValue:返回值类型
     * method:被调用的方法对象
     * arg1:被调用的方法的参数
     * target:被调用方法的目标对象 
      afterReturning(Object returnValue,Method method,Object[] args,Object target)  Throwable {
        
        System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被执行成功,返回值是"+returnValue);
        
 }

复制代码

spring配置文件(beans.xml):

复制代码

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    bean id="userService" class="com.wang.service.UserService"></bean="log"="com.wang.log.Log"="afterlog"="com.wang.log.AfterLog"aop:config<!--"*"为通配符表示所有方法,第一个* 表示任意返回值 第二个*表示所有方法      
        ".."表示任意个数的参数 -->
        aop:pointcut expression="execution(* com.wang.service.UserService.*())" id="pointcut"/>
           aop:advisor advice-ref pointcut-ref/>
    </>
beans>

复制代码

测试代码testDemo:

复制代码

   @Test
     test1(){
        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
        UserService userService=(UserService)context.getBean("userService");
        userService.add();
        userService.search();
    }

复制代码

运行测试可以看到控制台的打印结果:

com.wang.service.UserService中的add方法被执行
添加用户
com.wang.service.UserService中的add方法被执行成功,返回值是null

com.wang.service.UserService中的search方法被执行
查询用户
com.wang.service.UserService中的search方法被执行成功,返回值是null

在配置文件中,我们看到了一些这样的代码:

复制代码

 "*"为通配符表示所有方法      
        ".."表示任意个数的参数 >

复制代码

我们来介绍几个AOP的相关概念,这个就比较好理解了:

  • 切面(Aspect):在本例中.add(),delete(),等方法中都有一些代码,在真实的程序中这里不会只是简单的打印语句而是一些有意义的代码,这些代码可以看做是AOP的切面.
  • 通知(Advisor):本例中的两个日志类,这里可以成为拦截器,都是实现了某个*Advisor接口,这两个类就是指AOP中的通知,一旦Spring符合了条件,就会发出通知,与生活中我们所说的通知不同的是,Spring中的通知是带有执行代码的,能实现某种功能.
  • 切入点(pointcut): 在配置拦截器(<aop-config>)的时候,xml中配置了UserService中所有的方法都是用拦截器,这个配置是通过 spring中的一个已经写好的类完成的,这个类能配置对哪些方法使用拦截器,从那个地方"切入"进去.配置是可以使用通配符.

简而言之:"切入点"负责往"什么地方"插入代码,"通知"负责插入"什么代码".

 

  SpringAOP将公共的业务(如日志,安全)和领域业务结合,当执行领域业务时候把公共业务加进来,实现公共业务的重复利用,使得领域业务功能更加纯粹,程序员可以专注于领域业务.

  当然除了使用springAPI,我们也可以通过自定义的类,即不需要实现任何借口或继承任何类,的方式来实现上述功能:

  只需要一个Log类:

复制代码

 Log  {

     before(){
        System.out.println("执行方法前");
    }
    
     after(){
        System.out.println("执行方法后");
    }
}

复制代码

修改配置文件beans.xml中的<aop-config>为:

复制代码

    >
           aop:aspect ref="log"="execution(* com.wang.service.UserService.*(..))"/>
               aop:before method="before"aop:after ="after"aop:aspect>
       >

复制代码

执行上面的测试代码,打印出的结果是:

执行方法前
执行方法后
执行方法后

 其实这种配置方式还可以用注解来完成,下面介绍一下使用注解的方式,顺带讲一个环绕方法,它和before和after一样,不过是在某一个方法前后都会执行的代码:

  Log类:

复制代码

@Aspect
 Log  {
    @Before("execution(* com.wang.service.*.*(..))")
    );
    }
    @After("execution(* com.wang.service.*.*(..))");
    }
    
    @Around("execution(* com.wang.service.*.*(..))"public Object around(ProceedingJoinPoint pjp)  Throwable{
        System.out.println("环绕前");
        System.out.println("签名:"+pjp.getSignature());
        //执行目标方法
        Object proceed = pjp.proceed();
        System.out.println("环绕后");
        return proceed;
    }

复制代码

在beans.xml中,只需要将<aop-config>修改为一行代码:

复制代码

>
    <aop:aspectj-autoproxy/>
>

复制代码

打印结果如下,读者自行理解,这里对于around不再解释:

环绕前
签名:void com.wang.service.UserService.add()
环绕后
执行方法后

如果希望在before和after方法中得到当前执行方法的方法名或者参数的话,可以在bofore或者after方法中加一个参数,就是上面around方法中的参数,

  获得方法名:String methodName=pjp.getSignature().getName();

  获得方法参数列表:List<Object> list=Arrays.toList(pjp.getArgs());

Spring支持5种类型的通知注解:

  @Before:前置通知,在方法执行前执行

  @After:后置通知,在方法执行后执行(此注解标注的方法无法得到方法的返回值)

  @AfterRunning:返回通知,在方法返回结果之后执行(此注解标注的方法,可以获取到方法的返回值)

  @AfterThrowing:异常通知,在方法抛出异常后执行

  @Around:环绕通知,问绕着方法执行(环绕通知必须要有ProceedingJoinPoint类型的参数,且必须要有返回值,见上面).

原文地址:https://www.cnblogs.com/xiadongqing

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原理介绍,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。传统事务中回滚点的使...
今天小编给大家分享的是一文解析spring中事务的传播机制,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区别,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。Spring Cloud Netfli...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。第一步:整合pom文件,在S...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。List 坑列表 = new ArrayList(2);...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓存的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇...
本篇内容主要讲解“Spring中的@Autowired和@Resource注解怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学...
今天小编给大家分享一下SpringSecurity怎么定义多个过滤器链的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家
这篇文章主要介绍“Spring的@Conditional注解怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring的@Con...
这篇文章主要介绍了SpringCloudGateway的熔断限流怎么配置的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringCloud&nb...
今天小编给大家分享一下怎么使用Spring解决循环依赖问题的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考
这篇文章主要介绍“Spring事务及传播机制的原理及应用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Sp...
这篇“SpringCloudAlibaba框架实例应用分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价
本篇内容主要讲解“SpringBoot中怎么使用SpringMVC”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习...
这篇文章主要介绍“SpringMVC适配器模式作用范围是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringMVC
这篇“导入SpringCloud依赖失败如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要讲解了“SpringMVC核心DispatcherServlet处理流程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来
今天小编给大家分享一下SpringMVCHttpMessageConverter消息转换器怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以...
这篇文章主要介绍“Spring框架实现依赖注入的原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring框架...
本篇内容介绍了“Spring单元测试控制Bean注入的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下