Maison  >  Article  >  Java  >  Comment SpringBoot utilise la réflexion pour simuler IOC et getBean

Comment SpringBoot utilise la réflexion pour simuler IOC et getBean

王林
王林avant
2023-05-30 09:25:121025parcourir

spring basic idea IOC

Le deuxième est la réflexion Java. Le mécanisme de réflexion est un noyau d'implémentation important de Spring Aujourd'hui, lorsque j'examinais le cache de troisième niveau de Spring pour résoudre le problème de. références circulaires, j'ai trouvé un bean. Le cycle de vie d'un objet Java est très similaire au processus de génération d'objets Java et j'ai découvert que le processus d'une instance de bean à partir de zéro est très intéressant. un code extrêmement élégant pour réaliser l'utilisation de Reflection et diverses structures de données cartographiques réalisent la production de pipeline de beans, ce qui est très élégant, j'ai donc essayé d'utiliser la réflexion pour écrire un gadget qui génère à l'envers des objets d'instance.

Ensuite, vous devez connaître au préalable le processus de génération d'un objet :

Je résume le processus de création d'objet comme suit :

Vérifiez si le pool constant existe La référence symbolique de l'objet est utilisée pour déterminer s'il a subi le processus de chargement de classe. Sinon, le processus de chargement de classe est effectué.

Allouer de la mémoire pour les nouveaux objets (deux méthodes : collision de pointeurs et liste libre) et attribuez W à 0 pour les autres espaces mémoire à l'exception de l'en-tête de l'objet.

Définissez l'en-tête de l'objet.

Initialisation de l'objet, c'est le processus d'exécution de votre méthode constructeur et d'attribution des valeurs que vous souhaitez définir aux champs dont vous avez besoin.

Ajoutez les détails : dans le processus d'allocation de mémoire pour de nouveaux objets, tout d'abord, la taille de mémoire requise par un objet une fois le chargement de la classe terminé est en fait complètement déterminée. en java Divisez un morceau de mémoire tout aussi grand dans le tas, mais comment le diviser ? Si la disposition de la mémoire du tas Java est allouée dans un ordre strict, c'est-à-dire qu'un côté est utilisé et l'autre côté est libre, alors la mémoire sera allouée par collision de pointeur. Ce qu'on appelle le pointeur est collecté au niveau de la ligne de démarcation. entre la zone libre et la zone utilisée. Lorsque de la mémoire est requise, le pointeur recule jusqu'à ce que la longueur couverte par le déplacement soit égale à la taille de mémoire requise par l'objet Java et s'arrête et alloue. Mais que se passe-t-il si la disposition de la mémoire du tas Java est fragmentée et discontinue ? Nous ne pouvons conserver qu'une liste qui enregistre les informations sur la taille et l'emplacement de toutes les zones libres du tas Java. Lors de l'allocation, il nous suffit de trouver l'allocation de zone la plus appropriée pour les nouveaux objets.

La capacité du garbage collector et sa capacité à effectuer la compression et le tri de l'espace déterminent si le tas Java est régulier. Lorsque les collecteurs que nous utilisons sont Serial et Parnew, ils sont alloués par collision de pointeurs. Lorsque nous utilisons le garbage collector CMS, nous devons utiliser l'allocation de table de zone libre gênante.

Ici, nous nous concentrons sur le remplissage des attributs et des méthodes : l'âme d'un objet, ce sont ses attributs et ses méthodes :

Les attributs de base utilisés par l'ensemble de l'outil : # 🎜🎜#

    private static volatile Constructor<?> constructor;
    private static volatile Object newInstance;
    private static volatile Map<String, Method> methodMap;

Jetons d'abord un coup d'œil aux fonctions de ces méthodes :

  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;
        }
    }

Obtenez le constructeur du type Notez qu'il s'agit d'une construction sans argument si vous n'en avez pas. constructeur sans argument, c'est très utile. Une erreur peut être signalée, car nous ne savons pas combien d'attributs il possède, n'est-ce pas (rappelez-vous toujours que nous faisons de l'ingénierie inverse !!! Nous ne savons pas ce qu'il y a dans ce type ? !!! Tout est information apportée par réflexion)

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()));
        }
    }
# 🎜🎜#Récupérez les attributs et remplissez les valeurs des attributs. Les attributs sont également inclus ici.

 public static Method[] getMethodArray(Object dataType) {
        return dataType.getClass().getDeclaredMethods();
    }

Obtenez toutes les méthodes pour former un tableau de méthodes.

  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);
        }
    }

Enregistrez la méthode dans la collection de méthodes pour le stockage.

 public static Object useMethod(String methodName, @Nullable Object... parameters) throws Exception {
        return methodMap.get(methodName).invoke(newInstance, parameters);
    }

La méthode d'utilisation est par son nom.

    @SneakyThrows
    public static Object getBean(Object dataType, Map<String, Object> parameterMap) {
        fillValueToNewInstance(dataType, parameterMap);
        fillMethodMap(dataType);
        return newInstance;
    }

méthode 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"));
    }

Méthode de test. Les informations de type sont les suivantes :

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;;
    }
}

Les résultats du test sont les suivants :

Comment SpringBoot utilise la réflexion pour simuler IOC et getBeanIci, nous n'utilisons pas Personne personne = new Person(); L'objet est instancié par réflexion.

Je vais lister les méthodes de réflexion utilisées :

getDeclaredFields Récupère l'objet d'attribut de domaine

getName Récupère le nom de l'attribut

#🎜 🎜#getType Obtenez le fichier de bytecode du type d'attribut

setAccessible(true) Définissez le cracking par force brute et obtenez l'utilisation des attributs privés

getDeclaredMethods Obtenez tous les tableaux de méthodes# 🎜🎜#

getClass Récupère le fichier de bytecode

getConstructor Récupère le constructeur sans argument

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer