`
jinnianshilongnian
  • 浏览: 21504052 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2418680
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:3008784
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5639490
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:259916
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1597318
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:250219
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5858952
Group-logo
跟我学Nginx+Lua开...
浏览量:702004
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:785224
社区版块
存档分类
最新评论

在spring中获取代理对象代理的目标对象工具类

 
阅读更多

 

昨天晚上一哥们需要获取代理对象的目标对象,查找了文档发现没有相应的工具类,因此自己写了一个分享给大家。能获取JDK动态代理/CGLIB代理对象代理的目标对象。

 

 

问题描述::

 

我现在遇到个棘手的问题,要通过spring托管的service类保存对象,这个类是通过反射拿到的,经过实验发现这个类只能反射取得sservice实现了接口的方法,而extends类的方法一律不出现,debug后发现这个servie实例被spring替换成jdkdynmicproxy类,而不是原始对象了,,它里面只有service继承的接口方法,而没有extends 过的super class方法,怎么调用原生对象的方法!!!!!

 

用托管的spring service类调用getClass().getName()方法,发现输出都是$proxy43这类东西!!

 

 

通过此种方式获取目标对象是不可靠的,或者说任何获取目标对象的方式都是不可靠的,因为TargetSource,TargetSource中存放了目标对象,但TargetSource有很多种实现,默认我们使用的是SingletonTargetSource ,但还有其他的比如ThreadLocalTargetSourceCommonsPoolTargetSource 等等。

 

这也是为什么spring没有提供获取目标对象的API。

 

 

import java.lang.reflect.Field;

import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;

public class AopTargetUtils {

	
	/**
	 * 获取 目标对象
	 * @param proxy 代理对象
	 * @return 
	 * @throws Exception
	 */
	public static Object getTarget(Object proxy) throws Exception {
        
		if(!AopUtils.isAopProxy(proxy)) {
			return proxy;//不是代理对象
		}
		
		if(AopUtils.isJdkDynamicProxy(proxy)) {
			return getJdkDynamicProxyTargetObject(proxy);
		} else { //cglib
			return getCglibProxyTargetObject(proxy);
		}
		
		
        
	}


	private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
		Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        h.setAccessible(true);
        Object dynamicAdvisedInterceptor = h.get(proxy);
        
        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);
        
        Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
        
        return target;
	}


	private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
		Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
        h.setAccessible(true);
        AopProxy aopProxy = (AopProxy) h.get(proxy);
        
        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);
        
        Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
        
        return target;
	}
	
}

 

 

19
23
分享到:
评论
38 楼 g_man1990 2018-04-18  
1、org.springframework.aop.support.AopUtils#isAopProxy(Object),看源码,会先判断object instanceof SpringProxy
2、这是一个JdkDynamicProxy ,并木有实现SpringProxy,<bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
3、如果绕过1,然后执行到
AopProxy aopProxy = (AopProxy) h.get(proxy); 就报错了。Proxy.getInvocationHandler会得到ManagedEntityManagerFactoryInvocationHandler
37 楼 huangjf 2017-05-22  
LZ 想问个CGLIB代理的问题。
问题描述:我写了一个类,在类的方法上面使用了注解,注解实现了原生的Inherited ,然后用cglib实现代理,结果代理出来的对象在这个方法上面这个注解丢失了,想请问下,CGLIB是有这个问题吗,还是我使用的不对,下面贴身用CGLIB实现代理代码
public Object getInstance(Object target) {
       
        targetObject=target;
        Enhancer enhancer = new Enhancer();
        //this.target = target;
        enhancer.setSuperclass(target.getClass());
        //enhancer.setStrategy();
        // 回调方法
        enhancer.setCallback(this);
        return enhancer.create();
    }
36 楼 lzc_java 2015-06-24  
陈老师好~
35 楼 qiyangyang09 2014-12-08  
我也遇到反射获取方法问题。用了你这个工具类,可以从代理中获取相应的原始对象,学习了,谢谢你。
34 楼 oqyneil 2014-09-10  
Spring的aop代理对象都实现了Advised这个接口,可以直接将代理对象转成Advised类型后通过该接口提供的方法获取目标对象,我的项目使用这个方式来获取目标对象,貌似没什么问题
33 楼 huang_yong 2014-08-03  
我也遇到了这个问题,感谢开涛的解决方案!

在 Spring 中已经提供了该特性,可调用 org.springframework.aop.support.AopUtils 类的 isCglibProxy 方法来判断实例是否被 CGLib 动态代理了。

同样地,可以调用该类的 isJdkDynamicProxy 方法来判断实例是否被 JDK 动态代理。

若不知道是动态代理方式(CGLib 或 JDK),则可以使用 isAopProxy 方法来判断。

最后,也可使用 AopUtils 的 getTargetClass 方法获取被动态代理的目标类。
32 楼 jinnianshilongnian 2013-09-20  
qingse998 写道
lz你好我最近在看spring和动态代理,发现代理的类都不是原来的对象了,但是spring中可以通过ApplicationContext ct = new ClassPathXmlApplicationContext("spring.xml");
Student st = (Student)ct.getBean("student");得到目标对象,不知道和你说的是不是同一回事


目标对象和代理对象 类型是相同的(比如相同的接口/相同的类),所以赋值是成功

类代理: 生成目标对象的子类
接口代理:生成目标对象接口的实现
31 楼 qingse998 2013-09-20  
lz你好我最近在看spring和动态代理,发现代理的类都不是原来的对象了,但是spring中可以通过ApplicationContext ct = new ClassPathXmlApplicationContext("spring.xml");
Student st = (Student)ct.getBean("student");得到目标对象,不知道和你说的是不是同一回事
30 楼 zj05409 2013-04-27  
org.springframework.aop.support.AopUtils
29 楼 jinnianshilongnian 2012-11-14  
yangpeihai 写道
jinnianshilongnian 写道
yangpeihai 写道
jinnianshilongnian 写道
yangpeihai 写道
楼主牛人啊
请教个问题,cglib是否可以访问被代理类的private方法,多谢

我记得是不能代理私有方法的  因为私有方法只有自己能调用

通常我们一个方法如果业务逻辑比较复杂,都会拆成若干个private方法,如果我想通过cglib动态代理写日志,这些private方法就捕获不到啦,你是怎么处理这种日志记录private方法问题的,给点建议哈


这个是spring aop的限制,没什么好的方法,只能开放出去(如public)。
或者使用原生的aspectj。

什么是“原生的aspectj”,能不能搞个简单例子演示一下,多谢。。。

aspectj in action
28 楼 yangpeihai 2012-11-14  
jinnianshilongnian 写道
yangpeihai 写道
jinnianshilongnian 写道
yangpeihai 写道
楼主牛人啊
请教个问题,cglib是否可以访问被代理类的private方法,多谢

我记得是不能代理私有方法的  因为私有方法只有自己能调用

通常我们一个方法如果业务逻辑比较复杂,都会拆成若干个private方法,如果我想通过cglib动态代理写日志,这些private方法就捕获不到啦,你是怎么处理这种日志记录private方法问题的,给点建议哈


这个是spring aop的限制,没什么好的方法,只能开放出去(如public)。
或者使用原生的aspectj。

什么是“原生的aspectj”,能不能搞个简单例子演示一下,多谢。。。
27 楼 jinnianshilongnian 2012-11-14  
yangpeihai 写道
jinnianshilongnian 写道
yangpeihai 写道
楼主牛人啊
请教个问题,cglib是否可以访问被代理类的private方法,多谢

我记得是不能代理私有方法的  因为私有方法只有自己能调用

通常我们一个方法如果业务逻辑比较复杂,都会拆成若干个private方法,如果我想通过cglib动态代理写日志,这些private方法就捕获不到啦,你是怎么处理这种日志记录private方法问题的,给点建议哈


这个是spring aop的限制,没什么好的方法,只能开放出去(如public)。
或者使用原生的aspectj。
26 楼 yangpeihai 2012-11-14  
jinnianshilongnian 写道
yangpeihai 写道
楼主牛人啊
请教个问题,cglib是否可以访问被代理类的private方法,多谢

我记得是不能代理私有方法的  因为私有方法只有自己能调用

通常我们一个方法如果业务逻辑比较复杂,都会拆成若干个private方法,如果我想通过cglib动态代理写日志,这些private方法就捕获不到啦,你是怎么处理这种日志记录private方法问题的,给点建议哈
25 楼 jinnianshilongnian 2012-11-14  
yangpeihai 写道
楼主牛人啊
请教个问题,cglib是否可以访问被代理类的private方法,多谢

我记得是不能代理私有方法的  因为私有方法只有自己能调用
24 楼 yangpeihai 2012-11-14  
楼主牛人啊
请教个问题,cglib是否可以访问被代理类的private方法,多谢
23 楼 gigi_112 2012-09-26  
不错 楼主如果用个递归可能会更准确
22 楼 m635674608 2012-09-12  
当为cglib代理时,为什么不取CGLIB$CALLBACK1. target也也一样啊,,,
21 楼 jinnianshilongnian 2012-08-16  
zys0523 写道
受教了,楼主很牛
提个小意见.
Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); 
        h.setAccessible(true); 
        AopProxy aopProxy = (AopProxy) h.get(proxy); 

这三行可以换成JDK原生自带的
java.lang.reflect.Proxy.getInvocationHandler
    public static InvocationHandler getInvocationHandler(Object proxy)


JDK这种方式只能获取 InvocationHandler 这个呀,是获取不到目标对象的,目标对象实际存储在((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget(); 
20 楼 zys0523 2012-08-15  
受教了,楼主很牛
提个小意见.
Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); 
        h.setAccessible(true); 
        AopProxy aopProxy = (AopProxy) h.get(proxy); 

这三行可以换成JDK原生自带的
java.lang.reflect.Proxy.getInvocationHandler
    public static InvocationHandler getInvocationHandler(Object proxy)
19 楼 jinnianshilongnian 2012-08-01  
Pigwen 写道
jinnianshilongnian 写道
Pigwen 写道
晕,jdk的代理本身就只能搞接口,你让spring用cglib做代理不就好了啊。。。


嗯,如果是私有的呢

那就要反思下为什么会需要去反射这样的方法了。
你现在这个方案搞得了某个版本的cglib,其他版本的cglib万一又改变动态类名字的规则了喃,更何况还有javassist这些其他的动态代理框架存在?

没有完美的解决方案,现在他的需求就是这个样子。
设计目前就是这个样子。设计的问题除非他修改源代码 

相关推荐

    jdk代理,cgib代理和spring后处理bean的关系

    `AopTargetUtils`是Spring AOP模块中的一个工具类,它提供了用于处理AOP代理和目标对象的一些实用方法。例如,`AopTargetUtils.getTarget(Object proxy)`方法可以获取到代理对象背后的原始目标对象,这对于在处理...

    spring动态代理

    Spring 动态代理是 Spring 框架中的一个重要特性,它允许我们在运行时自动生成代理对象,以便在方法调用前后执行额外的操作,比如事务管理、AOP(面向切面编程)等。动态代理主要涉及两个核心接口:`java.lang....

    Spring源代码解析(五):Spring_AOP获取Proxy.doc

    本文将深入解析Spring AOP如何获取代理对象,即Proxy。 首先,我们需要理解AOP的核心概念: 1. **Advice**:通知,是切面实际执行的操作。在Spring中,Advice可以是Before、AfterReturning、AfterThrowing以及...

    JDK动态代理 spring aop 的原理

    在Java编程领域,JDK动态代理是实现动态创建代理对象的一种技术,它是Java标准库提供的一种强大工具。Spring AOP(面向切面编程)则是一种流行的应用框架,它利用动态代理来实现对业务代码的切面增强,如日志、事务...

    在自定义spring aop中使用el获取拦截方法的变量值。

    标题中的“在自定义Spring AOP中使用EL获取拦截方法的变量值”指的是在Spring的面向切面编程(AOP)中,通过Expression Language(EL,表达式语言)来访问被拦截方法的局部变量值。这通常涉及到Spring的代理机制、...

    spring boot内置工具类

    在Spring Boot框架中,内置了一些非常实用的工具类,这些工具类可以帮助开发者简化代码,提高开发效率。在本文中,我们将深入探讨其中的一些关键工具类,包括对象、数组、集合处理,文件、资源和IO流操作,以及反射...

    使用代理实现简易的spring aop功能

    在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员定义横切关注点,如日志、事务管理、权限检查等,并将它们模块化为可重用的切面。在这个例子中,我们将探讨如何使用动态代理来实现一个简单的...

    Spring Aop Advise方法(增强方法) 中获取目标方法的参数

    这篇博客文章“Spring Aop Advise方法(增强方法) 中获取目标方法的参数”可能详细解释了如何在Advise中获取被拦截方法的参数。为了深入理解这个主题,我们需要探讨以下几个关键知识点: 1. **AOP的基本概念**: - ...

    动态代理的方式注册到spring容器

    通过这种方式,Spring容器中的`userService` bean将是动态代理对象,当调用其方法时,会先执行我们在`invoke()`方法中定义的逻辑,包括服务降级处理和注解信息的获取。 总结来说,动态代理在Spring中提供了灵活的...

    Java动态代理(Spring Aop原理)

    - 调用Spring容器获取代理对象,执行业务方法时,相应的通知方法会被自动插入。 通过Java动态代理和Spring AOP,开发者能够轻松地实现代码的解耦,提高可维护性和复用性。在实际开发中,理解这些原理并合理运用,...

    Spring aop 基于schema的AOP支持及JoinPoint的使用、如何使用CGLIB代理

    Spring AOP在默认情况下,对于没有实现接口的类,会使用CGLIB库生成代理对象。CGLIB是一个强大的代码生成库,可以在运行时动态生成子类,从而实现对目标对象的代理。 1. **CGLIB工作原理** - CGLIB通过继承目标类...

    [#0x0042] Spring AOP学习(二):动态代理

    2. **获取代理接口**:代理对象需要实现与目标对象相同的接口,因此需要明确这些接口。 3. **生成代理类**:使用Proxy.newProxyInstance()方法,传入代理接口的类加载器、接口数组以及自定义的InvocationHandler,...

    java代理模式

    5. 使用Proxy.newProxyInstance()方法(动态代理)或直接创建代理类的实例(静态代理)来获取代理对象,并通过代理对象调用接口方法。 代理模式在Java开发中有着广泛的应用,比如在AOP(面向切面编程)中,Spring...

    使用Spring降低类之间的耦合

    3. **AOP代理**:Spring可以创建代理对象来拦截方法调用,这不仅支持AOP,还能在不修改原有类的基础上添加额外的行为。 4. **事件驱动**:Spring的ApplicationEvent和ApplicationListener机制允许组件之间通过发布和...

    Spring AOP的底层实现技术

    当我们通过Spring容器获取一个bean时,实际上是获取了它的代理对象。代理对象在调用目标方法前后,会根据通知类型执行相应的逻辑。比如,如果定义了一个前置通知,那么在调用目标方法之前,前置通知会被执行。 6. ...

    Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理)

    Java 动态代理是 Java 编程语言中的一种强大工具,广泛应用于 Spring AOP、Hibernate 数据查询、测试框架的后端 mock、RPC 远程调用、Java 注解对象获取、日志、用户鉴权、全局性异常处理、性能监控等领域。...

    spring-aop源码解读

    ProxyFactoryBean是Spring AOP用于创建代理对象的主要工具,它实现了BeanFactoryAware、BeanClassLoaderAware和FactoryBean接口,使其能够利用IOC容器的功能来查找并应用Advice和目标对象。 配置和使用...

    Spring-Reference_zh_CN(Spring中文参考手册)

    6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.1.1. @Configurable object的单元测试 6.8.1.2. 多application context情况下的处理 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来...

Global site tag (gtag.js) - Google Analytics