通过实例解析Spring argNames属性

最近学习Spring,一直不太明白Srping的切面编程中的的argNames的含义,经过学习研究后,终于明白,分享一下

需要监控的类:

package bean;
public class HelloApi {
  public void aspectTest(String a,String b){
    System.out.println("in aspectTest:" + "a:" + a + ",b:" + b);
  }
}

类HelloApi的aspectTest方法是需监控的方法,目标是调用前获取获得入参a和b的值,并打印出来。

切面类:

package aspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.String;

@Component
@Aspect
public class HelloApiAspect2 {

  @Pointcut(value="execution(* bean.HelloApi.aspectTest(..)) && args(a1,b2)",argNames="a1,b2")
  public void pointcut1(String a1,String b2){}

  @Before(value="pointcut1(a,b)",argNames="a,b")
  public void beforecase1(String a,String b){
    System.out.println("1 a:" + a +" b:" + b);
  }
  //注意和beforecase1的区别是argNames的顺序交换了
  @Before(value="pointcut1(a,b)",argNames="b,a")
  public void beforecase2(String a,String b){
    System.out.println("2 a:" + a +" b:" + b);
  }
}

测试类:

package UnitTest;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import bean.HelloApi;

public class Test1 {

  @Test
  public void aspectjTest1(){
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter2/aspectTest1.xml");
    HelloApi helloapi1 = beanFactory.getBean("helloapi1",HelloApi.class);
    helloapi1.aspectTest("a", "b");
  }
}

Spring的配置文件aspectTest.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:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    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/util
      http://www.springframework.org/schema/util/spring-util-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
  <context:component-scan base-package="aspect"></context:component-scan>

  <bean id="helloapi1" class="bean.HelloApi"></bean>
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

输出:

2 a:b b:a
1 a:a b:b
in aspectTest:a:a,b:b

说明:

  HelloApiAspect2定义了一个切面pointcut,切面表达式是execution(* bean.HelloApi.aspectTest(..)) && args(a1,b2),表示配对bean.HelloApi.aspectTest()方法,并且传入参数是2个。

args(a1,b2)另外一个作用,就是定义了aspectTest(String a,String b)方法对应表达式args(a1,b2)。定义了args(a1,b2),才能把目标方法aspectTest的参数传入到切面方法beforecase1的参数中,a参数对应a1,b参数对应b2。使用的方法是按顺序一一对应,aspectTest第一个参数对args第一个参数,aspectTest第2个参数对args第2个参数.

  argNames是可选的,如果没有argNames这个参数,而编译器设置了【在class文件生成变量调试信息】,则spring可以通过反射知道方法参数的名字,通过名字配对,Spring知道args(a1,b2)表达式里面的a1和b2,对应了pointcut1(String a1,String b2)方法里面的a1和b2。

  目标方法和切入方法的参数的关系是这样确立的:aspectTest(String a,String b) 与 args(a1,b2)关系是a对a1,b对b2(),args(a1,b2)与pointcut1(String a1,String b2)关系是args的a1对pointcut1的a1,args的a2对pointcut1的a2。解决了目标方法参数传入到切入方法参数的问题。

  但是,如果设置了argNames,Spring不再使用方法参数的名字来配对,使用argNames定义的顺序来定义pointcut1(String a1,String b2)的顺序,例如:argNames="a1,b2",a1在b2前面,表示pointcut1方法第一个参数是a1,第二个参数是b2。

  既然不设置argNames,Spring可以根据参数名字进行配对,为什么还需要配置argNames?因为Spring要知道方法的参数名,编译器必须设置了【在class文件生成变量调试信息】,如果没有设置,Spring就不知道pointcut1方法的参数名了,这个时候,Spring只知道参数的类型,Spring会使用参数的类型进行配对,如果出现2个参数都是同一个类型的情况,就会报AmbiguousBindingException异常。

  beforecase1和beforecase2的argNames设置的顺序交换了,调用beforecase1的顺序是beforecase1("a","b"),调用beforecase2的顺序是beforecase2("b","a"),所以最后的输出是

2 a:b b:a
1 a:a b:b

PS:

【class文件中生成变量调试信息】在myeclipse中打开windows-》preferences,设置如下:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • springboot中用fastjson处理返回值为null的属性值

    我们先来看代码: @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() { FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter()

  • Spring Boot jar中没有主清单属性的解决方法

    使用Spring Boot微服务搭建框架,在eclipse和Idea下能正常运行,但是在打成jar包部署或者直接使用java -jar命令的时候,提示了xxxxxx.jar中没有主清单属性: D:\hu-git\spring-xxx-xxx\target>java -jar spring-cloud-eureka-0.0.1-SNAPS HOT.jar spring-xxx-xxx-0.0.1-SNAPSHOT.jar中没有主清单属性 通过maven打jar包:mvn install, 或者在I

  • Spring读取配置文件属性实现方法

    一 前言 本篇内容包括spring 运行时读取配置文件的多种方式和SpEl表达式入门基础: 二运行时读取配置文件 spring 运行时读取配置文件值提供了2种方式 属性占位符(Property placeholder). Spring表达式语言(SpEL) 2.1 读取外部配置文件 使用 @PropertySource 注解可以读取导classpath下配置文件属性:参数如下 value是个字符串数组: ignoreResourceNotFound:如果设置为true, 配置文件未找到时不会报错

  • Spring通过配置文件和注解实现属性赋值

    前言 在实际开发当中,Spring中bean的属性直接赋值用的不是太多,整理这方面的资料,做一个小结,以备后续更深入的学习. 通过配置文件的方式 以配置文件的方式启动spring容器时,可以使用property标签的value给bean的属性赋值,赋值的形式有以下几种: <--通过context:property-placeholder将properties文件中的值加载的环境变量中(properties中的属性值最终是以环境变量的形式存储的)> <context:property-pl

  • 关于springboot 配置文件中属性变量引用方式@@解析

    这种属性应用方式是 field_name=@field_value@. 两个@符号是springboot为替代${}属性占位符产生,原因是${}会被maven处理,所以应该是起不到引用变量的作用. @@方式可以引用springboot非默认配置文件(即其他配置文件)中的变量: springboot默认配置文件是 src/main/resources/application.properties 补充知识:springboot项目使用@Value注解获取配置文件中的配置信息 application

  • 基于Spring boot @Value 注解注入属性值的操作方法

    本文主要介绍Spring @Value 注解注入属性值的使用方法的分析,文章通过示例代码非常详细地介绍,对于每个人的学习或工作都有一定的参考学习价值 在使用spring框架的项目中,@Value是经常使用的注解之一.其功能是将与配置文件中的键对应的值分配给其带注解的属性.在日常使用中,我们常用的功能相对简单.本文使您系统地了解@Value的用法. @Value注入形式 根据注入的内容来源,@ Value属性注入功能可以分为两种:通过配置文件进行属性注入和通过非配置文件进行属性注入. 非配置文件注

  • Spring@Value属性注入使用方法解析

    这篇文章主要介绍了Spring@Value属性注入使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在使用Spring框架的项目中,@Value是使用比较频繁的注解之一,它的作用是将配置文件中key对应的值赋值给它标注的属性.在日常使用中我们常用的功能都比较简单,本篇文章系统的带大家来了解一下@Value的使用方法. @Value注入支持形式 @Value属性注入功能根据注入的内容来源可分为两类:通过配置文件的属性注入和通过非配置文件

  • springboot yml定义属性,下文中${} 引用说明

    比如: yml中自定义一个域名属性: mytest: domainName: https://www.jb51.net 上面定义了之后, 在此配置文件中,就可通过 ${} 来代替域名了 defaultHead: ${mytest.domainName}/head.jpeg 补充知识:Java读取.yaml配置文件(使用@Value("${prefix_name}")) 添加lombok依赖 [注]lombok是可选的,但是如果yaml配合lombok使用将非常的方便,代码也很简洁 co

  • 通过实例解析Spring argNames属性

    最近学习Spring,一直不太明白Srping的切面编程中的的argNames的含义,经过学习研究后,终于明白,分享一下 需要监控的类: package bean; public class HelloApi { public void aspectTest(String a,String b){ System.out.println("in aspectTest:" + "a:" + a + ",b:" + b); } } 类HelloApi的

  • 通过实例解析spring bean之间的关系

    这篇文章主要介绍了通过实例解析spring bean之间的关系,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 两种关系:继承.依赖 一.继承关系 Address.java package com.gong.spring.beans.autowire; public class Address { private String city; private String street; public String getCity() { retur

  • 通过实例解析Spring组合注解与元注解

    这篇文章主要介绍了通过实例解析Spring组合注解与元注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.概述 1.1.Spring提供了大量的注解, 尤其是相同的注解用到各个类中,会相当的啰嗦: 1.2.元注解: 可以注解到别的注解上的注解: 组合注解: 被注解注解的注解称为 组合注解: 组合注解 具备 元注解 的功能,Spring的很多注解都可以作为元注解: 1.3.案例 package com.an.config; import co

  • 通过实例解析spring对象生命周期

    1.生命周期-@Bean指定初始化和销毁方法 配置时指定初始化及销毁方法: Bean中提供对应的初始化及销毁方法: package com.atguigu.bean; import org.springframework.stereotype.Component; @Component public class Car { public Car(){ System.out.println("car constructor..."); } public void init(){ Syst

  • 通过实例解析Spring Ioc项目实现过程

    0. Ioc https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html 主要是实现一个控制反转,耦合性大大降低. 1. 建maven项目 建立一个空的maven项目,然后pom.xml添加spring-context的依赖: <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -

  • 通过实例解析spring环绕通知原理及用法

    环绕通知: 它是spring框架为我们提供的一种可以在代码中手动控制增强部分什么时候执行的方式. 问题: 当我们配置了环绕通知之后,增强的代码执行了,业务核心方法没有执行. 分析: 通过动态代理我们知道在invoke方法中,有明确调用业务核心方法:method.invoke(). 我们配置的环绕通知中,没有明确调用业务核心方法. 解决: spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数在环绕通知执行时,spring框架会为我们提供该接口的

  • Spring事务隔离级别简介及实例解析

    本文研究的主要是Spring事务隔离级别(solation level)介绍及例子,具体如下. 当两个事务对同一个数据库的记录进行操作时,那么,他们之间的影响是怎么样的呢?这就出现了事务隔离级别的概念.数据库的隔离性与并发控制有很大关系.数据库的隔离级别是数据库的事务特性ACID的一部分.ACID,即原子性(atomicity).一致性(consistency).隔离性(isolation)和持久性(durability).Spring的事务隔离级别有四个:READ_UNCOMMITTED.RE

  • Spring用代码来读取properties文件实例解析

    有些时候,我们需要以Spring代码直接读取properties配置文件,那么我们要如何操作呢?下面我们来看看具体内容. 我们都知道,Spring可以@Value的方式读取properties中的值,只需要在配置文件中配置 org.springframework.beans.factory.config.PropertyPlaceholderConfigurer <bean id="propertyConfigurer" class="org.springframewo

  • Spring bean 加载执行顺序实例解析

    本文研究的主要是Spring bean 加载执行顺序的相关内容,具体如下. 问题来源: 有一个bean为A,一个bean为B.想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值. 如果只是在A里单纯的写着: private B b; private String name = b.funb(); 会报错说nullpointException,因为这个时候b还没被set进来,所以为null. 解决办法为如下代码,同时学习下spring中 InitializingBean

  • spring学习之@SessionAttributes实例解析

    本文研究的主要是spring学习之@SessionAttributes的相关内容,具体如下. 一.@ModelAttribute 在默认情况下,ModelMap 中的属性作用域是 request 级别是,也就是说,当本次请求结束后,ModelMap中的属性将销毁.如果希望在多个请求中共享 ModelMap 中的属性,必须将其属性转存到 session 中,这样ModelMap 的属性才可以被跨请求访问. spring 允许我们有选择地指定 ModelMap 中的哪些属性需要转存到 session

随机推荐