`

Spring Aop Advise方法(增强方法) 中获取目标方法的参数

阅读更多

Spring Aop Advise方法(增强方法) 中获取目标方法的参数

 

1. 概念 

   

   切面类: 一种特殊bean,通过aop配置,其中的方法(增强方法),会对目标bean的目标方法做一些增强处理

   (比如在目标方法之前或之后调用等).

   

   切入点(pointcut): 一种规则,普通bean中符合这种规则的方法,将成为上面切面类中所说的目标方法,接受切面类方法

   的特殊处理.

   

   增强方法(Advice),包括aop:befor,aop:after,aop:after-retuing,aop:around,aop:throwing等.

   

2. 配置片段:

     

<!-- AOP测试的chinese -->
            <bean id="chinese_aop" class="test.aop.Chinese" />
            <!-- 定义一个普通bean,作为切面bean -->
            <bean id="accessArgAspect" class="test.aop.aspect.AccessArgAspect" />
            <!-- AOP配置  --> 
            <aop:config>
              <!-- 配置切面aspect -->
              <aop:aspect id="aspect" ref="accessArgAspect">
                <aop:after-returning 
                  pointcut="execution(* test.aop.*.*(..))" 
                  method="access"
                  returning="retval"
                  arg-names="time,food,retval" 
                />
              </aop:aspect> 
            </aop:config>

       

    上面的配置中:

    <bean id="chinese_aop" class="test.aop.Chinese" />

    配置了普通的bean,该bean中的一些方法

    即将满足切入点配置规则,接受切面类中增强方法(Advice)的增强处理.

    

    <bean id="accessArgAspect" class="test.aop.aspect.AccessArgAspect" /> 定义一个切面类,

    切面类可以是一个普通的bean.

    

    <aop:config>

      <!--配置切面aspect,通过ref关联到前面配置的作为切面类的bean-->

      <aop:aspect id="aspect" ref="accessArgAspect">

        <!-- 配置一种aop:after-returning增强处理-->

        <aop:after-returning

          <!-- 切入点 规则,符合这个规则的普通bean中的方法将接受增强处理 -->

          pointcut="execution(*test.aop.*.*(..)) and args(food,time,..)"  

          <!-- 切面类中,作为增强处理的方法的名称 -->

          method="access"

          <!-- 普通bean,接受增强处理方法的返回值,void的类型被视为null --> 

          returning="retval" 

          <!-- 切面类中增强方法的参数名,这个配置可以省略 -->

          arg-names="time,food,retval"

        />

        

      </aop:aspect>

    </aop:config>

    

3. 参数绑定

   切面类 方法(增强方法)获取 目标方法(普通bean中接受增强方法处理的方法) 参数的方式称为参数绑定.

   

   (1) 增强方法 不需要传递参数,则不需要参数绑定.

   

   (2) 增强方法中,只有一个JoinPoint类型的参数,使用这种参数,也不需要参数绑定.

       因为, JoinPoint类有一些方法可以获取目标方法的调用信息(包括参数信息),比如:

       Object[] getArgs(),返回在执行目标方法时传递的参数

       Signature getSignature(),获取 目标方法的签名

       Object getTarget():返回被植入 增强处理的目标对象

       Object getThis(): 返回AOP框架为目标对象生成的代理对象(Spring AOP通过动态代理实现)

       

       假如是aop:around类型的增强处理方法,可以使用ProceedingJoinPoint作为参数,

       ProceedingJoinPoint除了有上述的几个方法外,还有一个proceed()方法,替代目标方法执行.

       

   (3) 增强方法中,有普通类型的参数,

       比如public void access(Date time,String food, String retval)

       这种增强方法,必须要在pointcut中通过配置args 和 returning,保证参数正确绑定.

       (returning只针对aop:after-returning类型的增强处理,其他的可以省略)

       (即,增强方法中出现的参数名必须在pointcut配置中都得到明确的配置,否则报异常)

       pointcut="execution(*test.aop.*.*(..)) and args(food,time,..)"

       中args(food,time,..)中的food和time是参数名,来自切面类的增强方法,不能乱写,

       必须和切面类中增强方法的参数名称一致,在切面类的增强方法参数列表中必须能找到.

       因为在增强方法public void access(Date time,String food, String retval)中,time是Date类型的,

       food是String类型的,所以pointcut(切入点)定义中and args(food,time,..)符合and前面的规则的同时

       还要符合args(food,time,..)的规则.

       args(food,time,..)表是所有 第一个参数是String类型,第二个参数是Date类型的方法才能称为目标方法.

       .. 表示可以有第三个,第四个, ... , 第n个参数,但是至少有两个参数(String,Date)

       所以需要注意的有:

       a. 切面类中的增强方法参数,必须要在pointcut中有明确指定,比如

          public void access(Date time,String food, String retval)

          这个方法中三个参数food,和time通过args指定了,retval表示aop:after-returning定义的目标函数的返回值.

       b. 明确指定了参数后,AOP框架在运行时能正确绑定参数,因为:

          and args(food,time,..)表示 只对一类目标方法的调用做增强处理,这种目标方法是:在准备调用这种目标方法时,

          实际传递给它的参数为food和time所表示的类型(food和time必须在增强方法的参数列表中找到,这样就根据增强方法确定了food和time的类型).

          并且,传递参数的顺序也要是和args(food,time,..)中一致.这样在调用目标方法时,至少会按顺序传递food,time两个参数,

          AOP框架可以将这两个参数传递给 增强方法.

   

   (4) 增强方法中 有 JoinPoint和普通类型参数,

       则必须将JoinPoint类型的参数作为第一个参数,普通参数从第二个开始.

       其他的处理方式,按照上面(3)中仅含有普通参数的方式处理.

       

 主要代码;

package test.aop;

import java.util.Date;

/**
 * 
 * 普通bean的接口
 *
 */
public interface Person
{
  String sayHello(String name);
  void eat(String food, Date time);
  void eat2(String food, Date time,String test);
}

 

package test.aop;

import java.util.Date;

/**
 * 
 *一个普通bean,eat方法和sayHello方法,是需要被切入,动态影响的
 *
 */
public class Chinese implements Person
{

  @Override
  public void eat(String afood, Date atime)
  {
    System.out.println("正在吃: " + afood + ", 时间是: " + atime);
  }

  @Override
  public String sayHello(String name)
  {
    return name + " Hello, Spring AOP.";
  }
  
  public void eat2(String afood, Date atime,String test)
  {
    System.out.println("eat2 --------- 正在吃: " + afood + ", 时间是: " + atime + ", eat2里面的test= " + test);
  }

}

 

package test.aop.aspect;

import java.util.Arrays;
import java.util.Date;

import org.aspectj.lang.JoinPoint;

/**
 * 
 * 定义切面类,处理test.aop.Chinese.eat()
 *
 */
public class AccessArgAspect
{
  
  //普通的 增强方法
  public void access(Date time,String food, String retval)
  {
    System.out.println("");
    
    System.out.println("目标方法中 String 参数为: " + food);
    System.out.println("目标方法中 String 参数为: " + time);
    System.out.println("目标方法 返回值: " + retval);
    
    System.out.println("模拟记录日志...");
    
  }
  
  /**
   * 第一个参数为JoinPoint类型的增强方法,JoinPoint必须为第一个参数
   * @param jp
   * @param time
   * @param food
   * @param retval
   */
  public void accessWithJoinPoint(JoinPoint jp,Date time,String food)
  {
    System.out.println("");
    System.out.println("JoinPoint.getArgs()获取参数列表:" + Arrays.toString(jp.getArgs()));
    
    System.out.println("JoinPoint jp ---- 目标方法中 String 参数为: " + food);
    System.out.println("JoinPoint jp ---- 目标方法中 String 参数为: " + time);
    
    System.out.println("JoinPoint jp ---- 模拟记录日志...");
    
  }
}

 

package test.aop;

import java.util.Date;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 
 * AOP客户端测试类
 *
 */
public class TestClient
{
  public static void main(String[] args)
  {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
    System.out.println(ctx);
    
    Person person = ctx.getBean("chinese_aop",Person.class);
    
    person.sayHello("jack");
    
    person.eat("米饭",new Date());
    
    person.eat2("米饭",new Date(),"test");
  }
}

 

<?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-3.0.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> 
            
            <!-- 小试牛刀 property使用 name,value-->
            <bean id="personService" class="test.spring.PersonService">
              <property name="name" value="wawa"></property>
            </bean>
            
            <!-- 
                  设值注入
                property使用 name,ref ,
                ref也是一个bean的id,ref 可以在stoneAxe和steelAxe之间随意切换,而不用修改java代码 
            -->
            <bean id="chinese" class="test.ioc.setter.Chinese">
              <property name="axe" ref="steelAxe"></property>
            </bean>
            <bean id="stoneAxe" class="test.ioc.setter.StoneAxe" /> 
            <bean id="steelAxe" class="test.ioc.setter.SteelAxe" /> 
            
            <!-- 
                构造注入
                constructor-arg标签,ref ,
                ref也是一个bean的id,ref 可以在stoneAxe和steelAxe之间随意切换,而不用修改java代码
                constructor-arg 也可以配置value,表示传递给构造函数的是一个 普通的值,而不是另一个bean 
            -->
            <bean id="chinese1" class="test.ioc.constructor.Chinese">
              <constructor-arg ref="steelAxe" /> 
            </bean>
            
            <!-- 国际化 -->
           <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
              <property name="basenames" >
                <list>
                  <!-- 这里的value可带路径   -->
                  <value>message</value>
                </list>
              </property> 
            </bean>
            
            <!-- 
              ApplicationContext的事件机制 
                在Spring中配置了实现ApplicationListener接口的Bean,
              Spring容器就会把这个Bean当成容器事件的监听器
            -->
            <bean class="test.springevent.EmainNotifier" /> 
            
            <!-- bean中获取 ApplicationContext引用-->
            <bean name="beangetappcontext" class="test.bean.get.appcontext.BeanGetAppContext" />
            
            <!-- AOP测试的chinese -->
            <bean id="chinese_aop" class="test.aop.Chinese" />
            <!-- 定义一个普通bean,作为切面bean -->
            <bean id="accessArgAspect" class="test.aop.aspect.AccessArgAspect" />
            <!-- AOP配置  --> 
            <aop:config>
              <!-- 配置切面aspect -->
              <aop:aspect id="aspect" ref="accessArgAspect">
                <aop:after-returning 
                  pointcut="execution(* test.aop.*.*(..)) and args(food,time,..)" 
                  method="access"
                  returning="retval"
                  arg-names="time,food,retval" 
                />
                
                <aop:before 
                  pointcut="execution(* test.aop.*.*(..)) and args(food,time,..)" 
                  method="accessWithJoinPoint"
                />
                
              </aop:aspect> 
            </aop:config>
             
</beans> 

 

工程文件注:

 

使用Spring 3.2.0的所有ja包,

3.2.0的srping包,做AOP需要依赖(Spring 3.2.0中去除了依赖包,需要自己找)

com.springsource.org.aopalliance-1.0.0.jar,下载地址http://ebr.springsource.com/repository/app/bundle/version/detail?name=org.springframework.aop&version=3.2.0.RELEASE

还有,3.0.2的com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar包,

下载3.0.2版本的依赖包以后,找

spring-framework-3.0.2.RELEASE-dependencies (1)\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE这个目录里面有      

          

附件中工程已包含所有需要的jar包

         

分享到:
评论

相关推荐

    在自定义spring aop中使用el获取拦截方法的变量值。

    标题中的“在自定义Spring AOP中使用EL获取拦截方法的变量值”指的是在Spring的面向切面编程(AOP)中,通过Expression Language(EL,表达式语言)来访问被拦截方法的局部变量值。这通常涉及到Spring的代理机制、...

    spring aop jar 包

    6. **代理(Proxy)**:代理是AOP的核心,它是目标对象的增强版本,负责在调用目标方法前后执行通知。 在使用Spring AOP时,我们可以通过XML配置或注解的方式来定义切面。例如,可以使用`@Aspect`注解定义一个切面...

    springboot+aspect实现springaop拦截指定方法.zip

    SpringBoot结合AspectJ实现SpringAOP拦截指定方法的知识点涵盖了多个方面,这包括Spring AOP的基本概念、SpringBoot的应用、切点(Pointcut)与通知(Advice)的定义、自定义注解以及AspectJ的使用。以下是这些知识...

    Java利用spring aop进行监测方法执行耗时

    使用 Spring AOP 进行方法耗时监测的好处有以下几点: 1. 代码实现简单,易于维护:使用 Spring AOP 可以将耗时监测的逻辑与业务逻辑进行解耦,避免业务逻辑代码的冗余和代码维护难度的提高。 2. 安全性高:使用 ...

    Spring3.0.5扩展支持AOP获取HttpServletResponse

    在Spring 3.0.5版本中,Spring扩展了对AOP的支持,特别是在处理HTTP响应时,可以通过AOP来获取`HttpServletResponse`对象。`HttpServletResponse`是Servlet API中的核心接口,它用于封装服务器向客户端发送的响应...

    spring aop切面拦截指定类和方法实现流程日志跟踪

    在上述代码中,我们定义了一个名为`SpringAopLog`的切面类,并通过注解指定了哪些方法会在目标方法执行前后被调用。在`afterReturn`方法中,根据不同的方法名来记录不同的日志信息。 #### 四、总结 通过Spring AOP...

    Spring AOP 16道面试题及答案.docx

    连接点(Joint Point)是程序执行过程中的特定点,通常在Spring AOP中,它代表一个方法的执行。而切入点(Point Cut)是匹配连接点的规则,它定义了一组连接点的集合,可以是一个断言或表达式。Advice与切入点关联,...

    简单spring aop 例子

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...

    Spring  AOP实现方法大全

    该接口只有一个方法`before()`,它接受三个参数:`Method`对象代表即将执行的方法,`Object[] args`是方法的参数,`Object target`是目标对象。在`before()`方法中,可以执行预处理操作,如日志记录。如果`before()`...

    Spring AOP完整例子

    在Spring中,我们通常使用表达式或者注解来定义切点。例如,我们可以使用`@Before`、`@After`、`@Around`、`@AfterReturning`和`@AfterThrowing`等注解来声明前置、后置、环绕、返回后和异常后通知,这些通知在切点...

    Spring中的AOP(五)——在Advice方法中获取目标方法的参数

    本篇主要探讨如何在AOP的Advice方法中获取目标方法的参数。 首先,理解AOP的基本概念至关重要。在Spring AOP中,切面(Aspect)是关注点的模块化,它包含切点(Pointcut)和通知(Advice)。切点定义了应用中哪些...

    死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理(csdn)————程序.pdf

    Spring AOP 是一种面向切面编程的技术,它允许我们在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行增强。在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态...

    AOP修改方法的参数

    在这个类的 `invoke` 方法中,我们可以访问到目标方法的参数,并对其进行修改。 3. **创建代理对象**:通过 `Proxy.newProxyInstance` 方法创建代理对象。传递给这个方法的是业务接口的类加载器、接口数组以及 `...

    spring aop实例annotation方法实现

    在Spring中,可以使用`@Aspect`注解来定义一个切面类,然后在该类中定义通知方法。 ```java @Aspect public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logBefore...

    spring aop依赖jar包

    在Spring AOP中,我们可以通过定义切面(Aspect)来封装横切关注点,从而实现代码的解耦和模块化。切面通常包含通知(Advice)、切点(Pointcut)和织入(Weaving)等概念。 首先,让我们详细了解一下Spring AOP的...

    Spring AOP实现机制

    自定义类加载器允许我们在特定条件下加载类,例如,当类需要被CGLIB增强时,自定义类加载器可以在加载过程中应用AOP增强。 ### 4. Spring AOP配置 Spring AOP的配置可以通过XML或注解方式进行: - **XML配置**: ...

    Spring AOP之5种增强方法应用范例

    环绕通知是Spring AOP中最强大的一种增强方式,它允许在方法调用前后执行自定义的逻辑,并可以选择是否执行目标方法。环绕通知通过`@Around`注解实现,需要实现`ProceedingJoinPoint`接口的`proceed()`方法来调用...

    spring aop的demo

    总的来说,这个Spring AOP的Demo旨在帮助我们理解如何在实际项目中利用Spring AOP进行功能增强,它展示了切面的定义、通知的使用,以及如何在Spring环境中配置和启用AOP。通过学习和实践这个Demo,我们可以更好地...

    Spring AOP配置事务方法

    Spring AOP 配置事务方法 Spring AOP(Aspect-Oriented Programming,面向方面编程)是一种编程范式,它允许开发者在不修改源代码的情况下,增强和修改应用程序的行为。 Spring AOP 提供了一种灵活的方式来实现事务...

Global site tag (gtag.js) - Google Analytics