SpringBoot がリフレクションを使用して IOC と getBean をシミュレートする方法

王林
リリース: 2023-05-30 09:25:12
転載
1034 人が閲覧しました

Spring の基本的なアイデア IOC

2 つ目は Java リフレクションです。リフレクション メカニズムは Spring の重要な実装コアです。今日、循環参照の問題を解決するために Spring の第 3 レベルのキャッシュを調べたときに、次のことがわかりました。 Bean のライフサイクル。これは Java オブジェクトの生成プロセスと非常によく似ています。次に、Bean の作成プロセスを調べてみると、Bean インスタンスを最初から作成するプロセスが非常に興味深いことがわかりました。Spring は非常にエレガントなコードを使用して、このマップデータ構造はBeanのパイプライン生成を実現しており非常にエレガントなので、リフレクションを利用してインスタンスオブジェクトを逆生成するガジェットを書いてみました。

次に、オブジェクトを生成するプロセスを事前に理解する必要があります。

オブジェクトの作成プロセスを次のように要約します。

オブジェクトへのシンボリック参照があるかどうかを確認します。定数プールを取得し、クラスロード処理を行っているかどうかを判定し、クラスロード処理を行っていない場合はクラスロード処理を実行します。

新しいオブジェクトにメモリを割り当て (ポインタ衝突とフリー リストの 2 つの方法 )、W を次のオブジェクトに割り当てます。オブジェクトヘッダーを除くその他のメモリ空間の場合は 0。

オブジェクトヘッダーを設定します。

オブジェクトの初期化。これは、コンストラクター メソッドを実行し、定義する値を必要なフィールドに割り当てるプロセスです。

詳細を追加: 新しいオブジェクトにメモリを割り当てるプロセスでは、まず、クラスのロードが完了した後にオブジェクトが必要とするメモリ サイズが完全に決定されます。メモリを割り当てるプロセスは、実際にはJava ヒープ、同じサイズのメモリを分割しますが、どのように分割すればよいでしょうか? Java ヒープのメモリ レイアウトが厳密な順序で割り当てられている場合、つまり、一方が使用され、もう一方が空きである場合、メモリはポインタの衝突によって割り当てられ、いわゆるポインタが境界線で収集されます。空き領域と使用済み領域の間を移動し、メモリが必要になると、ポインタは移動した長さが Java オブジェクトが必要とするメモリ サイズに等しくなるまで後方に移動し、停止して割り当てられます。しかし、Java ヒープのメモリ レイアウトが断片化されていて不連続な場合はどうなるでしょうか?すべての Java ヒープ空き領域のサイズと位置情報を記録したリストを維持することしかできず、割り当てるときは、新しいオブジェクトに最適な領域割り当てを見つけるだけで済みます。

ガベージ コレクターの機能と、ガベージ コレクターが領域の圧縮と並べ替えを実行できるかどうかによって、Java ヒープが正規かどうかが決まります。使用するコレクタが Serial や Parnew の場合はポインタ衝突により確保されますが、CMS ガベージコレクタを使用する場合は面倒な空き領域テーブルの確保が必要になります。

ここでは、プロパティとメソッドの入力に焦点を当てます。オブジェクトの本質はそのプロパティとメソッドです。

ツール全体で使用されるコア プロパティ:

    private static volatile Constructor<?> constructor;
    private static volatile Object newInstance;
    private static volatile Map<String, Method> methodMap;
ログイン後にコピー

まず、これらのメソッドの機能を見てみましょう:

  public static Constructor<?> getConstructor(Object dataType) {
        Class<?> typeClass = dataType.getClass();
        try {
            Constructor<?> constructor = typeClass.getConstructor();
            constructor.setAccessible(true);
            return constructor;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            return null;
        }
    }
ログイン後にコピー

型のコンストラクターを取得します。これはパラメーターなしのコンストラクターであることに注意してください。パラメーターなしのコンストラクターがない場合は、おそらくそれが可能です。エラーを報告するには、私たちもわからないからです。属性はいくつありますか? (私たちはリバース エンジニアリングであることを常に忘れないでください!!! この型に何が含まれているかはわかりません!!! すべてがもたらされる情報です反射による)

public static void fillValueToNewInstance(Object dataType, Map<String, Object> initialMap) throws Exception {
        constructor = getConstructor(dataType);
        Class<?> typeClass = dataType.getClass();
        Field[] declaredFields = typeClass.getDeclaredFields();
        Iterator<Field> fieldIterator = Arrays.stream(declaredFields).iterator();
        newInstance = constructor.newInstance();
        while (fieldIterator.hasNext()) {
            Field field = fieldIterator.next();
            field.setAccessible(true);
            if (initialMap != null)
                field.set(newInstance, initialMap.get(field.getName()));
        }
    }
ログイン後にコピー

属性を取得し、属性値を入力します。属性もここに含まれます。

 public static Method[] getMethodArray(Object dataType) {
        return dataType.getClass().getDeclaredMethods();
    }
ログイン後にコピー

すべてのメソッドを取得してメソッド配列を形成します。

  public static void fillMethodMap(Object dataType) {
        methodMap = new HashMap<>();
        Method[] methodArray = getMethodArray(dataType);
        Iterator<Method> iterator = Arrays.stream(methodArray).iterator();
        while (iterator.hasNext()) {
            Method method = iterator.next();
            method.setAccessible(true);
            methodMap.put(method.getName(), method);
        }
    }
ログイン後にコピー

メソッドをメソッド コレクションに保存して保存します。

 public static Object useMethod(String methodName, @Nullable Object... parameters) throws Exception {
        return methodMap.get(methodName).invoke(newInstance, parameters);
    }
ログイン後にコピー

使用方法は名前を渡すことです。

    @SneakyThrows
    public static Object getBean(Object dataType, Map<String, Object> parameterMap) {
        fillValueToNewInstance(dataType, parameterMap);
        fillMethodMap(dataType);
        return newInstance;
    }
ログイン後にコピー

getBean メソッド。

  public static void main(String[] args) throws Exception {
        Map<String,Object> map = new HashMap<>();
        map.put("name","xu");
        map.put("age",Integer.valueOf(18));
        map.put("sex",&#39;女&#39;);
        Person bean = (Person) getBean(new Person(), map);
        System.out.println(bean.toString());
        System.out.println(useMethod("toString"));
    }
ログイン後にコピー

テスト方法。型情報は次のとおりです:

class Person {
    private String name;
    private Integer age;
    private Character sex;
    //无参构造绝对不能少
    public Person() {
    }
    @Override
    public String toString() {
        return "Person{" +
                "name=&#39;" + name + &#39;\&#39;&#39; +
                ", age=" + age +
                ", sex=" + sex +
                &#39;}&#39;;
    }
}
ログイン後にコピー

テスト結果は次のとおりです:

SpringBoot がリフレクションを使用して IOC と getBean をシミュレートする方法

ここでは、 person person = new Person(); を使用しません。オブジェクトをインスタンス化するには、オブジェクトのインスタンス化を実装する Reflection を使用します。

そこで使用されるリフレクション メソッドをリストします。

getDeclaredFields ドメイン属性オブジェクトを取得します。

getName 属性名を取得します。

getType 単語を取得します。属性タイプ セクション コード ファイル

setAccessible(true) ブルート フォース クラッキングを設定し、プライベート属性の使用を取得します

getDeclaredMethods すべてのメソッド配列を取得します

getClass バイトコード ファイルを取得します

getConstructor パラメーターなしのコンストラクターを取得します

以上がSpringBoot がリフレクションを使用して IOC と getBean をシミュレートする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート