坑向: 关于在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的红色下划线提示(变成警告也行):
在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
XML实现Spring AOP,你需要进行以下步骤: 1. 配置AOP命名空间:在XML文件的顶部,添加以下命名空间声明: ```xmlxmlns:aop="http://www.springframework.org/schema/aop" ``` 2. 导入AOP模式的架构定义:在XML文件的顶部,添加以下架构定义: ```xmlhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd``` 3. 定义切面和通知:在XML文件,使用`<aop:config>`元素定义切面和通知。例如,以下示例定义了一个切面和一个前置通知: ```xml<aop:config> <aop:aspect id="myAspect" ref="myAspectBean"> <aop:before method="beforeAdvice" pointcut="execution(* com.example.MyClass.myMethod(..))" /> </aop:aspect> </aop:config> ``` 其,`myAspectBean`是切面对象的引用,`beforeAdvice`是前置通知方法的名称,`com.example.MyClass.myMethod(..)`是切入点表达式,表示要拦截的目标方法。 4. 声明目标对象:在XML文件,声明需要应用切面的目标对象。例如: ```xml<bean id="myTargetBean" class="com.example.MyClass" /> ``` 5. 启用AOP代理:在XML文件,使用`<aop:aspectj-autoproxy>`元素启用AOP代理功能。例如: ```xml<aop:aspectj-autoproxy /> ``` 这样,当Spring容器启动,它会自动创建代理对象,并将切面织入到目标对象实现AOP的功能。 请注意,上述示例仅展示了基本的AOP配置,实际使用可能涉及更复杂的切入点、通知类型和切面配置。你可以根据具体需求进行配置和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值