[Done]Spring @Pointcut 切点调用不到(SpringAOP嵌套方法不起作用) 注意事项
今天在开发过程中,遇到一个问题卡了很久,测试代码如下:
package spring.pointcut; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut; /**
* @Description: Pointcut测试
* @Author: qionghui.fang
* @Date: 2018/10/23 上午10:10
*/
@Aspect
public class TargetMonitor { // 配置方法1
// @Pointcut("execution(* spring.pointcut.Target.onEvent(String))")
// private void anyMethod() {}
// @Around("anyMethod()") //配置方法2
@Around("execution(* spring.pointcut.Target.onEvent(..))")
public Object monitor(ProceedingJoinPoint point) throws Throwable {
System.out.println("before");
try {
return point.proceed();
} finally {
System.out.println("after");
}
}
}
目标类:
public class Target {
public void otherEvent(){
System.out.println("Call otherEvent()");
}
public boolean onEvent(Integer type, Long Value){
System.out.println("Call onEvent(Integer type, Long Value)");
for (int i=0; i<=3; i++){
onEvent("");
}
System.out.println("End Call onEvent(Integer type, Long Value)");
return true;
}
public boolean onEvent(String type){
System.out.println("Call onEvent(String type)");
return true;
}
}
Main方法:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring.xml");
Target target = (Target) ctx.getBean("target");
System.out.println("\n*****************************");
target.onEvent(1,1L);
System.out.println("\n*****************************");
target.onEvent("");
System.out.println("\n*****************************");
target.otherEvent();
System.out.println("\n*****************************");
}
}
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="target" class="spring.pointcut.Target"/> <bean id="monitor" class="spring.pointcut.TargetMonitor"/> <!-- 基于@AspectJ切面的驱动器 -->
<aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
结果输出:
22:14:25.092 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'target' *****************************
22:14:25.096 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'monitor'
before
Call onEvent(Integer type, Long Value)
Call onEvent(String type)
Call onEvent(String type)
Call onEvent(String type)
Call onEvent(String type)
End Call onEvent(Integer type, Long Value)
after *****************************
before
Call onEvent(String type)
after *****************************
Call otherEvent() *****************************
问题描述:

在目标类里有两个同名的onEvent方法,下面这个是目标切点方法,但是系统调用时,方法入口是上面的onEvent方法,所以怎么都执行不到想要的逻辑。
其实想一想动态代理,是代理的类这一层级,关于类中方法的相互调用,是不能侵入这么深的。
注意:切点方法当前仅当在类执行入口时才能被调用,而非类内部的其他接口调用。
原理跟踪,跟踪生成的动态代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import spring.dynamicproxy.IFace; public final class Target1$Proxy extends Proxy implements Target {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m5;
private static Method m0; static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("spring.dynamicproxy.Target").getMethod("onEvent");
m4 = Class.forName("spring.dynamicproxy.Target").getMethod("onEvent1");
m5 = Class.forName("spring.dynamicproxy.Target").getMethod("otherEvent");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
} public Target1$Proxy(InvocationHandler var1) throws {
super(var1);
} public final boolean onEvent() throws {
try {
return (Boolean)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final boolean onEvent1() throws {
try {
return (Boolean)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final void otherEvent() throws {
try {
super.h.invoke(this, m5, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} }
上述省略了部分其他方法,大家关注这个动态代理类内容,
JDK的动态代理核心是生成了一个新的代理类,这个代理类基础Proxy类,实现了目标对象的接口,而在具体方法执行时,
调用super.h.invoke,这里的super.h 是指我们初始化动态代理的InvocationHandler,这里有点绕,大家要好好理解。
也就是说动态代理生效的方法是,当调用代理类Target.m的目标方法时,其实执行的是ProxyTarget.m,
这样我们在切点中round前后的逻辑就可以执行到。
但是当执行round中的super.h.invoke时,这个方法里执行的是原始类的原生逻辑,比如执行上述例子的onEvent1,
但onEnvent1中调用onEvent时,是执行的this.onEvent,而非ProxyTarget.onEvent,
这便是为什么上述例子无法执行的底层核心原因。
这篇文章也描述了类似的问题:https://blog.csdn.net/bobozai86/article/details/78896487
解决办法:
1、在调用点使用代理类,而非this调用:

main中获取容器对象的测试方法:

2、思考业务层面,是否可以切在更内层的方法。
本质还是要理解动态代理的实现原理。
以上。
[Done]Spring @Pointcut 切点调用不到(SpringAOP嵌套方法不起作用) 注意事项的更多相关文章
- Spring.net 间接调用被AOP拦截的方法失效(无法进入aop的拦截方法)
.下面的tx要定义 <objects xmlns="http://www.springframework.net" xmlns:db="http://www.spr ...
- 使用Spring boot开发RestFul 风格项目PUT/DELETE方法不起作用
在使用Spring boot 开发restful 风格的项目,put.delete方法不起作用,解决办法. 实体类Student @Data public class Student { privat ...
- Spring事务:调用同一个类中的方法
问题: 如果同一个类中有方法:methodA(); methodB().methodA()没有开启事务,methodB()开启了事务 且methodA()会调用methodB(). 那么,method ...
- Spring异步调用原理及SpringAop拦截器链原理
一.Spring异步调用底层原理 开启异步调用只需一个注解@EnableAsync @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTI ...
- Spring AOP 切点(pointcut)表达式
这遍文章将介绍Spring AOP切点表达式(下称表达式)语言,首先介绍两个面向切面编程中使用到的术语. 连接点(Joint Point):广义上来讲,方法.异常处理块.字段这些程序调用过程中可以抽像 ...
- Spring学习(十六)----- Spring AOP实例(Pointcut(切点),Advisor)
在上一个Spring AOP通知的例子,一个类的整个方法被自动拦截.但在大多数情况下,可能只需要一种方式来拦截一个或两个方法,这就是为什么引入'切入点'的原因.它允许你通过它的方法名来拦截方法.另外, ...
- spring框架学习笔记5:SpringAOP示例
1.导包: 导入spring中的这两个包 再导入其他包(网上下载): 2.准备目标对象: package service; public class UserServiceImpl implement ...
- Spring AOP切点表达式用法总结
1. 简介 面向对象编程,也称为OOP(即Object Oriented Programming)最大的优点在于能够将业务模块进行封装,从而达到功能复用的目的.通过面向对象编程,不同的模 ...
- CXF整合Spring之JaxWsProxyFactoryBean调用
1.见解 1.1 客户端的接口代码还一定要和服务端的接口代码一样,连注解都要一样,不够灵活 1.2 当客户端访问服务器的请求地址时,如果服务端没有对应的地址,就会报错,但是又没有cxf的异常捕获处理 ...
随机推荐
- spring mvc Controller中使用@Value无法获取属性值
在使用spring mvc时,实际上是两个spring容器: 1,dispatcher-servlet.xml 是一个,我们的controller就在这里,所以这个里面也需要注入属性文件 org.sp ...
- Extjs GridPanel 监听事件 行选中背景
Extjs设置GridPanel选中行背景色和选中单元格背景色 var view = grid.getView(); view.getRow(index).style.backgroundColor ...
- 【java】关于Map的排序性的一次使用,有序的Map
关于Map的排序性的一次使用,有序的Map >>>>> hashmap是按key的hash码排序的,而treemap是利用comparator 进行key的自然排序的 / ...
- mysql数据库字符集初步理解
1.MySQL(4.1以后版本) 服务器中有六个关键位置使用了字符集的概念,他们是: 1.client 2.connection 3.database 4.results 5.server 6.sys ...
- quartz 中JobExecutionContext的使用
假如execute方法中需要一些额外的数据怎么办?比如说execute 中希望发送一封邮件,但是我需要知道邮件的发送者.接收者等信息? 存在两种解决方案: 1.JobDataMap类: 每个Jo ...
- Serializable java序列化
Bean Serializable Interface 的接口让BEAN可以串行化,将其变成一个可保存为以后使用的二进制流.当一个BEAN被系列化到磁盘上或者其他任何地方,其状态被保存起来,其中的属性 ...
- GIF图片合集(用于网络请求图片用)
GIF图片合集(用于网络请求图片用)
- springmvc最简单的搭建,初学者必看
web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi=" ...
- dao层的泛型实现(2种方法)
一: package com.wzs.test2.dao; import java.util.List; public interface CommonDAO { public <T> v ...
- Command 命令模式 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...