坑向: 关于在IDEA中 以XML形式 实现Spring AOP编程时,在xml配置文件中给 连接点的前置通知before 传递参数时出现Unbound pointcut parameter错误的排查

Posted 新来的大狮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了坑向: 关于在IDEA中 以XML形式 实现Spring AOP编程时,在xml配置文件中给 连接点的前置通知before 传递参数时出现Unbound pointcut parameter错误的排查相关的知识,希望对你有一定的参考价值。

坑向: 关于在IDEA中 以XML形式 实现Spring AOP编程时,在xml配置文件中给 连接点的前置通知before 传递参数时出现Unbound pointcut parameter错误的排查

1. 环境介绍

1.1 开发环境

IntelliJ IDEA 2018.3 x64

1.2 spring-config.xml的 beans标签的 相关命名空间属性

<?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: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-4.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd ">
<!-- 此处省略 -->
</beans>

2.1 错误介绍

在为 连接点 ProceedingJoinPoint 以XML形式 添加 可以传递参数的 before方法时,编译环境提示异常:Unbound pointcut parameter ‘user2’

2.2 原目的 及 错误相关的 代码环境 介绍

2.2.1 原目的

实现基于XML形式的Spring AOP编程,为连接点的添加 带有参数的 前置通知 before

具体思路为: 为一个Bean 创建 输出其信息的接口,然后实现该接口,最终设计一个切面类对该实现的接口方法进行一定的拦截和管理,使其前置通知可以传递被拦截的连接点方法的参数。

2.2.2 错误相关的 代码环境

① 使用的Bean类 User2.java

package com.castle.beans;

import java.io.Serializable;

public class User2 implements Serializable 
    private Long id;
    private String userName;
    private String note;

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getUserName() 
        return userName;
    

    public void setUserName(String userName) 
        this.userName = userName;
    

    public String getNote() 
        return note;
    

    public void setNote(String note) 
        this.note = note;
    

    @Override
    public String toString() 
        return id + " " + userName + ": " + note;
    

② 设计的接口和相应实现类 User2XMLService.java 与 User2XMLServiceImp.java

package com.castle.service;

import com.castle.beans.User2;

public interface User2XMLService 
    void printUser2(User2 user2);


//=================================================================

package com.castle.service;

import com.castle.beans.User2;

public class User2XMLServiceImp implements User2XMLService 
    @Override
    public void printUser2(User2 user2) 
        System.err.println(user2);
    

③ 设计的切面类 User2XMLAspect.java

package com.castle.aspect;

import com.castle.beans.User2;
import org.aspectj.lang.ProceedingJoinPoint;

import static com.castle.tools.PrintTool.*;

public class User2XMLAspect 
    public void before(User2 user2)
        println("XML before... [" + user2.getUserName() + "]");
    

    public void around(ProceedingJoinPoint joinPoint)
        println("XML around before...");
        try
            joinPoint.proceed();
        catch (Throwable e)
            e.printStackTrace();
        
        println("XML around after...");
    

    public void after()
        println("XML after...");
    

    public void afterThrowing()
        println("XML after throwing...");
    

    public void afterReturning()
        println("XML after returning...");
    

④ 最终的spring-config2.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: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-4.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd ">

    <bean id="user2" class="com.castle.beans.User2">
        <property name="id" value="99"/>
        <property name="userName" value="Rugal"/>
        <property name="note" value="I am the king of fighters"/>
    </bean>

    <bean id="service1" class="com.castle.service.User2XMLServiceImp"/>

    <bean id="aspect1" class="com.castle.aspect.User2XMLAspect"/>

    <aop:config>
        <aop:aspect ref="aspect1">
            <aop:pointcut id="printUser2" expression=
                    "execution(* com.castle.service.User2XMLServiceImp.printUser2(..))"/>
            <aop:before method="before" pointcut=
                    "execution(* com.castle.service.User2XMLServiceImp.printUser2(..)) and args(user2)"/>
            <aop:around method="around" pointcut-ref="printUser2"/>
            <aop:after method="after" pointcut-ref="printUser2"/>
            <aop:after-returning method="afterReturning" pointcut-ref="printUser2"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="printUser2"/>
        </aop:aspect>
    </aop:config>

</beans>

⑤ 测试代码

    /**
     * 测试使用纯XML方法,无注解实现Spring的AOP编程,对连接点方法进行拦截管理
     */
    public static void test17()
        ApplicationContext xmlContext = new ClassPathXmlApplicationContext("spring-config2.xml");
        User2XMLService service = (User2XMLService) xmlContext.getBean("service1");
        User2 user2 = (User2) xmlContext.getBean("user2");
        service.printUser2(user2);
    

3.1 错误排查(发现编写的代码正确)

仔细检查
在切面类中关于给before方法传递的参数 为 user2

public void before(User2 user2)
        println("XML before... [" + user2.getUserName() + "]");
    

在xml配置文件中指定切点的表达式中 要求获取的参数 也为 user2没有发现名称不一致

<aop:before method="before" pointcut=
                    "execution(* com.castle.service.User2XMLServiceImp.printUser2(..)) and args(user2)"/>

3.2 带着错误执行程序

结果成功运行,并且 切点拦截的连接点方法 被成功执行了 所设计的前置通知before(), 其参数user2的userName也被 成功传递!

public void before(User2 user2)
        println("XML before... [" + user2.getUserName() + "]");
    

userName 被成功提取出来为 Rugal 【此时依然存在Unbound pointcut parameter错误】

4. 编译环境提示错误的原因分析 和 解决方案

4.1 原因分析

也许关于切点的表达式书写正确,并无错误,是编译器或者xml配置文件参照的xsd文件存在一些bug。
即:

<aop:before method="before" pointcut=
                    "execution(* com.castle.service.User2XMLServiceImp.printUser2(..)) and args(user2)"/>

此语句本无编译错误,IDEA出现误报

4.2 Unbound pointcut parameter错误解决方案

① 修改 IDEA编译的 检查配置, 取消AOP子标签下的 Advice parameters检查

② 压制参数名称检查 ArgNamesErrorsInspection

即添加代码

			<!--suppress ArgNamesErrorsInspection -->
            <aop:before method="before" pointcut=
                    "execution(* com.castle.service.User2XMLServiceImp.printUser2(..)) and args(user2)"/>

最终没有了Error的红色下划线提示(变成警告也行):

以上是关于坑向: 关于在IDEA中 以XML形式 实现Spring AOP编程时,在xml配置文件中给 连接点的前置通知before 传递参数时出现Unbound pointcut parameter错误的排查的主要内容,如果未能解决你的问题,请参考以下文章

坑向: 关于对Oracle数据库新建用户后,进行角色授予GRANT “CONNECT“, “RESOURCE“后,用户仍然没有指定角色的相关权限,致拒绝登录ORA-01045问题的探究

关于在Spring中通过注解形式的IoC容器 纯使用 @ComponentScan注解实现对包的自动扫描,实现非XML形式的 注解形式装配Bean类

IDEA Spring boot Maven打包发布

IDEA使用Maven工具打包带有外部jar包时出错 - 提示程序包不存在和找不到符号

SpringBoot常用注解解析

generator mybatis逆向工程