Spring中獲取被代理的對象

Spring中獲取被代理的對象

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

  1. System.setProperty("cglib.debugLocation","E:\\data\\spring")用來指定 代理類class文件生成位置,在CGLIB中也能夠這麼用。
  2. getTrueTargetFrom0等方法是如何獲取被代理對象UserService的,有必定CGLIB基礎以後,代理類中存在回調類,屬性CGLIB$CALLBACK_x(x 爲數字),Spring生成 代理類時候會將 被代理的UserService保存起來在某些CGLIB$CALLBACK_x中. 這些須要查看源碼纔能有個輪廓的瞭解。

獲取Spring被代理對象何時可能會用到?

​ 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被代理了以後就進入到了真正的UserServicegetDao 方法.blog

​ 提示:代碼不規範,同事兩行淚,這種寫法不太規範僅供出現問題時定位.繼承

相關文章
相關標籤/搜索