La différence entre les trois méthodes d'injection de @Autowired et l'utilisation de base de l'annotation @Inject

La différence entre les trois méthodes d'injection de @Autowired

Lors de l'utilisation de l'annotation @Autowired pour l'injection de dépendances dans Spring, il existe généralement trois méthodes d'injection :

  1. Constructeurs autocâblés (injection de constructeur)
  2. Méthodes Autowired (injection de setter)
  3. Champs câblés automatiquement (injection de propriétés)

@Autowired trois méthodes d'injection

1. Injection de constructeur

public class MovieRecommender {
    
    

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
    
    
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

​ Parce que le cycle de déclaration du Bean comporte grosso modo les étapes suivantes : instanciation -> affectation d'attribut -> initialisation -> destruction . C'est-à-dire que la méthode constructeur doit d'abord être exécutée, puis l'injection de dépendances d'attribut est effectuée. Pendant le processus d'instanciation, si l'objet d'instance correspondant au paramètre de construction est introuvable dans le conteneur ioc, la fonction constructeur ne sera pas exécutée Cela garantit que tant qu'un objet est instancié, toutes ses dépendances ne seront pas nulles (à condition que toutes les variables membres soient injectées en tant que paramètres de construction ou aient des valeurs initiales qui leur sont attachées). Ainsi, dans cette façon d'utiliser, des problèmes peuvent être trouvés et des exceptions levées pendant la phase d'instanciation de l'objet , ce qui est différent de l'injection d'attributs mentionnée ci-dessous.

À partir de Spring Framework 4.3, si le bean cible ne définit initialement qu'un seul constructeur, il n'est alors pas nécessaire d'utiliser l'annotation @Autowired sur un tel constructeur. Cependant, si plusieurs constructeurs sont disponibles et qu'il n'y a pas de constructeur par défaut, au moins un des constructeurs doit être annoté avec @Autowired pour indiquer au conteneur lequel utiliser.

L'annotation Lombok implémente l'injection de constructeur

Si vous trouvez l'injection de constructeur difficile à écrire, vous pouvez utiliser l'annotation @RequiredArgsConstructor de Lombok pour générer automatiquement un constructeur avec @Autowired.

Remarque : Les dépendances injectées par le constructeur utilisant lombok doivent être finales ou décorées avec @NonNull, sinon lombok n'injectera pas ces dépendances.

@RequiredArgsConstructor(onConstructor=@_(@Autowired))
@Controller
public class BasicController {
    
    

    private final UserService userService;
    
    @RequestMapping("/hello")
    @ResponseBody
    public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {
    
    
        return "Hello " + name;
    }
	// ...
}

2. Injection de passeur

public class SimpleMovieLister {
    
    

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
    
    
        this.movieFinder = movieFinder;
    }

    // ...
}

L'injection de setter sera effectuée après le processus d'instanciation. Bien qu'en théorie cela puisse rendre la dépendance nulle, en fait Spring n'attribuera pas de valeurs nulles à la dépendance. Si la dépendance n'existe pas dans le conteneur ioc, Spring lèvera une exception. Par conséquent, l'injection de setter et l'injection de constructeur ont le même effet en termes d'utilisation, et elles lèveront des exceptions dans le temps. La différence est que le temps d'injection de dépendance est différent, l'un est en phase d'instanciation et le l'autre est en phase de cession de propriété.

​L'injection Setter n'a pas d'exigences spécifiques concernant le nom de la méthode et le nombre de paramètres de la méthode, tels que :

public class MovieRecommender {
    
    

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
    
    
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

L'exemple ci-dessus appartient toujours à une injection setter.

3. Injection d'attributs

public class MovieRecommender {
    
    

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
    
    
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

L'injection de propriété et l'injection de constructeur peuvent être utilisées en même temps. L'injection d'attributs sera rappelée par idea Field injection is not recommended.

@Autowired temps d'exécution : l'injection de propriété consiste essentiellement à injecter directement dans le champ par réflexion. Étant donné que la méthode de réflexion ne peut être appelée pour l'injection qu'après la création de l'objet, le temps d'exécution est après la création de l'objet.

Il peut y avoir des dangers cachés dans cette approche :

Question une
@Autowired
private User user;

private String company;

public UserDaoImpl(){
    
    
    this.company = user.getCompany();
}

Aucune erreur ne sera signalée pendant le processus de compilation, mais une NullPointerException sera signalée après l'exécution.

Lorsque Java initialise une classe, il suit l'ordre des variables statiques ou des blocs d'instructions statiques -> variables d'instance ou blocs d'instructions d'initialisation -> constructeurs -> @Autowired. Ainsi, lorsque la méthode constructeur de cette classe est exécutée, l'objet utilisateur n'a pas encore été injecté et sa valeur est toujours nulle.

question 2

Lorsque nous injectons automatiquement des attributs, si nous écrivons le mauvais type de dépendance, l'exception de pointeur nul ne peut être trouvée que lors de l'utilisation de cette dépendance, au lieu de la signaler à temps après l'exécution du projet, ce qui nous empêche de résoudre le problème à temps.

Résumer

  1. Pour les dépendances nécessaires, il est recommandé d'utiliser l'injection de constructeur, et elle est généralement utilisée avec final pour garantir que l'injection de dépendances est immuable. L'utilisation de l'injection de constructeur peut exprimer très clairement les dépendances d'une classe, rendant les dépendances du code plus évidentes et plus faciles à maintenir. De plus, cette approche améliore la testabilité de votre code puisque toutes les dépendances requises doivent être déclarées dans le constructeur.
  2. Pour les dépendances facultatives, l’injection setter est recommandée. L'injection Setter peut éviter l'accès direct aux propriétés de classe, obtenant ainsi une meilleure encapsulation.
  3. L'injection d'attributs peut réduire le code d'une classe, la rendant plus concise et facile à comprendre, mais l'injection d'attributs peut être injectée comme nulle. Ces erreurs ne se produiront que lorsqu'elles seront utilisées. De plus, l'injection d'attributs présente également des dangers cachés.
  4. L'injection de constructeur et de setter est recommandée, tandis que l'injection de propriété n'est pas recommandée à moins que la dépendance ne soit très simple et claire.

Utilisez @Inject au lieu de @Autowired

À partir de Spring 3.0, Spring prend en charge les annotations standard JSR-330 (injection de dépendances). Ces annotations sont analysées de la même manière que les annotations Spring. Pour les utiliser, introduisez les packages jar pertinents dans le fichier pom.

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

Comme @Autowired, vous pouvez utiliser @Inject sur les propriétés, les méthodes de définition et les paramètres du constructeur.

import javax.inject.Inject;

public class SimpleMovieLister {
    
    

    private MovieFinder movieFinder;

    @Inject
    public void setMovieFinder(MovieFinder movieFinder) {
    
    
        this.movieFinder = movieFinder;
    }

    public void listMovies() {
    
    
        this.movieFinder.findMovies(...);
        // ...
    }
}

De plus, vous pouvez obtenir des dépendances via un chargement paresseux via la méthode Provider.get() et l'utiliser :

import javax.inject.Inject;
import javax.inject.Provider;

public class SimpleMovieLister {
    
    

    private Provider<MovieFinder> movieFinder;

    @Inject
    public void setMovieFinder(Provider<MovieFinder> movieFinder) {
    
    
        this.movieFinder = movieFinder;
    }

    public void listMovies() {
    
    
        this.movieFinder.get().findMovies(...);
        // ...
    }
}

Vous pouvez également utiliser @Named pour spécifier une classe d'implémentation spécifique :

import javax.inject.Inject;
import javax.inject.Named;

public class SimpleMovieLister {
    
    

    private MovieFinder movieFinder;

    @Inject
    public void setMovieFinder(@Named("main") MovieFinder movieFinder) {
    
    
        this.movieFinder = movieFinder;
    }

    // ...
}

Priorité d'injection :

  1. Correspondance par type
  2. Match par qualification
  3. Correspondance par nom

Étant donné que l'annotation @Inject n'a aucun attribut, une erreur sera signalée lors de l'échec du chargement du bean requis, ce qui est différent de @Autowired.

référence

  • https://docs.spring.io/spring-framework/docs/5.3.27/reference/html/core.html#beans-autowired-annotation
  • https://juejin.cn/post/7023618746501562399
  • https://blog.csdn.net/qq_39249094/article/details/121028234

Je suppose que tu aimes

Origine blog.csdn.net/m0_63323097/article/details/130463814
conseillé
Classement