IntelliJ IDEA 2018.3 x64
<?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>
在为 连接点 ProceedingJoinPoint 以XML形式 添加 可以传递参数的 before方法时,编译环境提示异常:Unbound pointcut parameter ‘user2’
实现基于XML形式的Spring AOP编程,为连接点的添加 带有参数的 前置通知 before
具体思路为: 为一个Bean 创建 输出其信息的接口,然后实现该接口,最终设计一个切面类对该实现的接口方法进行一定的拦截和管理,使其前置通知可以传递被拦截的连接点方法的参数。
① 使用的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);
}
仔细检查
在切面类中关于给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)"/>
结果成功运行,并且 切点拦截的连接点方法 被成功执行了 所设计的前置通知before(), 其参数user2的userName也被 成功传递!
public void before(User2 user2){
println("XML before... [" + user2.getUserName() + "]");
}
userName 被成功提取出来为 Rugal 【此时依然存在Unbound pointcut parameter错误】
也许关于切点的表达式书写正确,并无错误,是编译器或者xml配置文件参照的xsd文件存在一些bug。
即:
<aop:before method="before" pointcut=
"execution(* com.castle.service.User2XMLServiceImp.printUser2(..)) and args(user2)"/>
此语句本无编译错误,IDEA出现误报
① 修改 IDEA编译的 检查配置, 取消AOP子标签下的 Advice parameters检查
② 压制参数名称检查 ArgNamesErrorsInspection
即添加代码
<!--suppress ArgNamesErrorsInspection -->
<aop:before method="before" pointcut=
"execution(* com.castle.service.User2XMLServiceImp.printUser2(..)) and args(user2)"/>