Spring中获取被代理的对象spring
### 获取Spring被代理对象的JAVA工具类工具
Spring采用CGLIB或者JDK动态代理来实现AOP,那如何获取 被代理对象?经过ApplicationContext.getBean()
获取到的对象都是 利用字节码动态生成的 加强对象,那假如咱们有场景获取 被代理的对象,方式以下: (封装到工具类形式里面,直接经过getTrueTargetFrom0
便可调用,须要强转一下类型.)debug
import org.springframework.aop.TargetSource; import org.springframework.aop.framework.AdvisedSupport; import org.springframework.cglib.proxy.MethodInterceptor; import java.lang.reflect.Field; public class SpringUtils { public static Object getTrueTargetFrom0(Object obj){ try { //获取第一个拦截器 Field field = obj.getClass().getDeclaredField("CGLIB$CALLBACK_0"); field.setAccessible(true); MethodInterceptor interceptor = (MethodInterceptor) field.get(obj); //获取拦截器的属性advised Field advised = interceptor.getClass().getDeclaredField("advised"); advised.setAccessible(true); AdvisedSupport advisedSupport = (AdvisedSupport) advised.get(interceptor); TargetSource targetSource=null; if (advisedSupport!=null) { targetSource = advisedSupport.getTargetSource(); } return targetSource!=null?targetSource.getTarget():null; } catch (Exception e) { e.printStackTrace(); } return null; } public static Object getTrueTargetFrom1(Object obj){ try { //获取第二个拦截器 Field field = obj.getClass().getDeclaredField("CGLIB$CALLBACK_1"); field.setAccessible(true); MethodInterceptor interceptor = (MethodInterceptor) field.get(obj); //获取拦截器的属性advised Field advised = interceptor.getClass().getDeclaredField("target"); advised.setAccessible(true); Object result = advised.get(interceptor); return result; } catch (Exception e) { e.printStackTrace(); } return null; } public static Object getTrueTargetFrom3(Object obj){ try { //获取第四个拦截器 Field field = obj.getClass().getDeclaredField("CGLIB$CALLBACK_3"); field.setAccessible(true); MethodInterceptor interceptor = (MethodInterceptor) field.get(obj); //获取拦截器的属性advised Field advised = interceptor.getClass().getDeclaredField("target"); advised.setAccessible(true); Object result = advised.get(interceptor); return result; } catch (Exception e) { e.printStackTrace(); } return null; } }
效果截图代理
效果说明: 三个方法效果同样.code
System.setProperty("cglib.debugLocation","E:\\data\\spring")
用来指定 代理类class文件生成位置,在CGLIB中也能够这么用。getTrueTargetFrom0
等方法是如何获取被代理对象UserService
的,有必定CGLIB基础以后,代理类中存在回调类,属性CGLIB$CALLBACK_x
(x 为数字),Spring生成 代理类时候会将 被代理的UserService
保存起来在某些CGLIB$CALLBACK_x
中. 这些须要查看源码才能有个轮廓的了解。 CGLIB代理是基于继承或者实现接口的方式,咱们可能只须要知道 class 属性就能生成代理类,这样作带来的问题:
父类(被代理类)的属性可能咱们 只能经过 方法 来获取,好比有个dao
属性,不是private
修饰类型的,咱们不想经过getDao
来获取,想直接调用 属性 ,那可能就是空的. 下面看下例子,对象
@Service public class UserService { @Autowired public UserDao dao; public void addUser(){ System.out.println("添加用户"); } public UserDao getDao() { return dao; } }
这样一个类可能不符合代码编写,可是用来介绍实验效果够了。 好比咱们 ApplicationContext.getBean(UserService.class).getDao
是可以获取到注入的DAO,可是ApplicationContext.getBean(UserService.class).dao
输出的就是null. 缘由很简单,CGLIB加强的是方法,dao确定就是空的,getDao被代理了以后就进入到了真正的UserService
的 getDao 方法.blog
提示:代码不规范,同事两行泪,这种写法不太规范仅供出现问题时定位.继承