Подтвердить что ты не робот

Объясните, почему инжектор конструктора лучше других вариантов

В книге Pro Spring 3, Глава 4 - Введение IOC и DI в разделе Spring - стр. 59, в разделе "Ввод инжекции преобразователя или конструктора" в абзаце говорится:

Spring, обеспечивают механизм для обеспечения того, чтобы все зависимости определялись, когда вы используете Setter Injection, но, используя Injection Constructor, вы утверждаете требование для зависимости в агностически-контейнере "

Не могли бы вы объяснить с примерами

4b9b3361

Ответ 1

Класс, который принимает требуемую зависимость как аргумент конструктора, может быть создан только в том случае, если этот аргумент предоставлен (у вас должно быть предложение охраны, чтобы убедиться, что аргумент не равен нулю.) Поэтому конструктор применяет требование зависимости, независимо от того, вы используете Spring, что делает его контейнером-агностиком.

Если вы используете инъекцию установщика, установщик может или не может быть вызван, поэтому экземпляр никогда не может быть связан с его зависимостью. Единственный способ заставить вызывающего абонента использовать @Required или @Autowired , что является специфическим для Spring и поэтому не является агрегированным с контейнером.

Итак, чтобы ваш код не зависел от Spring, используйте аргументы конструктора для вставки.

Обновление: Spring 4.3 будет выполнять неявное впрыскивание в сценариях с одним конструктором, делая ваш код более независимым из Spring, не требуя вообще аннотации @Autowired.

Ответ 2

(...), используя конструктор Injection, вы утверждаете требование для зависимости в агностически-контейнере

Это означает, что вы можете применять требования ко всем введенным полям без использования какого-либо конкретного решения для контейнеров.


Пример инъекции сеттера

При вводе вставки требуется специальная аннотация spring @Required.

@Required

Отмечает метод (как правило, метод set JavaBean) как " required": то есть метод setter должен быть настроен так, чтобы он был введен с зависимостями со значением.

Использование

import org.springframework.beans.factory.annotation.Required;

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

@Named
public class Foo {

    private Bar bar;

    @Inject
    @Required
    public void setBar(Bar bar) {
        this.bar = bar;
    }
}

Пример внедрения конструктора

Все обязательные поля определены в конструкторе, чистом решении Java.

Использование

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

@Named
public class Foo {

    private Bar bar;

    @Inject
    public Foo(Bar bar) {
        this.bar = bar;
    }

}

Ответ 3

  • Частичная зависимость: может быть введена с использованием инсталляции установщика, но конструктор это невозможно. Предположим, что в классе есть 3 свойства, которые имеют 3 метода конструктора и сеттера arg. В этом случае, если вы хотите передавать информацию только для одного свойства, это возможно только с помощью метода setter.
  • Переопределение: Вставка Setter переопределяет инъекцию конструктора. Если мы используем как инсталляцию конструктора, так и установки, контейнер IOC будет использовать инъекцию установщика.
  • Изменения: Мы можем легко изменить значение путем инъекции установщика. Он не создает новый экземпляр bean всегда как конструктор. Таким образом, инъекция установщика является гибкой, чем инъекция конструктора.

Ответ 4

Чтобы сделать его простым, скажем, что мы можем использовать инъекцию зависимостей на основе конструктора для обязательных зависимостей и инъекции на основе сеттера для необязательных зависимостей. Это эмпирическое правило!

Скажем, например.

Если вы хотите создать экземпляр класса, вы всегда делаете его со своим конструктором. Поэтому, если вы используете инъекцию на основе конструктора, единственный способ создать экземпляр класса - через этот конструктор. Если вы передаете зависимость через конструктор, становится очевидным, что это обязательная зависимость.

С другой стороны, если у вас есть метод setter в классе POJO, вы можете или не можете установить значение для своей переменной класса с использованием этого метода setter. Это полностью зависит от ваших потребностей. то есть он является необязательным. Поэтому, если вы передаете зависимость через метод setter класса, это подразумевает, что это необязательная зависимость. Надеюсь, это ясно!

Ответ 5

Включение конструктора используется, когда класс не может функционировать без зависимого класса.

Вставка свойств используется, когда класс может функционировать без зависимого класса.

В качестве конкретного примера рассмотрим ServiceRepository, который зависит от IService для выполнения своей работы. Поскольку ServiceRepository не может функционировать с пользой без IService, имеет смысл впрыснуть его через конструктор.

Тот же класс ServiceRepository может использовать Logger для отслеживания. ILogger можно вводить через инъекцию свойств.

Другими распространенными примерами вложения свойств являются ICache (другой аспект в терминологии АОП) или IBaseProperty (свойство в базовом классе).

Ответ 6

Используя конструктор Injection, вы утверждаете требование для зависимости в агностически-контейнере

Нам нужна гарантия от контейнера IoC, что перед использованием любого bean необходимо выполнить инъекцию необходимого beans.

В стратегии установки вставки мы доверяем контейнеру IoC, который сначала создаст bean, но сделает инъекцию прямо перед использованием bean с использованием методов setter. И инъекция выполняется в соответствии с вашей конфигурацией. Если вы каким-то образом не указали какой-либо beans для ввода в конфигурацию, инъекция не будет выполнена для этих beans, и ваш зависимый bean не будет функционировать соответствующим образом, когда он будет использоваться!

Но в стратегии конструктор-инъекция контейнер налагает (или должен налагать), чтобы правильно предоставлять зависимости при построении bean. Это было рассмотрено как "контейнерно-агностическая манера" , так как мы должны предоставлять зависимости при создании bean, что делает видимость зависимости независимой от любого контейнера IoC.

Edit:

Q1: И как предотвратить создание контейнера bean конструктором с null значениями вместо отсутствия beans?

У вас нет возможности пропустить любой <constructor-arg> (в случае Spring), потому что вы наложили контейнер IoC, чтобы предоставить все аргументы конструктора, необходимые для соответствия предоставленному конструктору для создания bean. Если вы предусмотрели null в своем <constructor-arg> намеренно. Тогда нет ничего, что может сделать с ним контейнер IoC!

Ответ 7

Этот пример может помочь:

Класс контроллера:

@RestController
@RequestMapping("/abc/dev")
@Scope(value = WebApplicationContext.SCOPE_REQUEST)
public class MyController {
//Setter Injection
@Resource(name="configBlack")
public void setColor(Color c) {
    System.out.println("Injecting setter");
    this.blackColor = c;
}

public Color getColor() {
    return this.blackColor;
}

public MyController() {
    super();
}

Color nred;
Color nblack;

//Constructor injection
@Autowired
public MyController(@Qualifier("constBlack")Color b, @Qualifier("constRed")Color r) {
    this.nred = r;
    this.nblack = b;
}

private Color blackColor;

//Field injection
@Autowired
private Color black;

//Field injection
@Resource(name="configRed")
private Color red;

@RequestMapping(value = "/customers", produces = { "application/text" }, method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.CREATED)
public String createCustomer() {
    System.out.println("Field injection red: " + red.getName());
    System.out.println("Field injection: " + black.getName());
    System.out.println("Setter injection black: " + blackColor.getName());

    System.out.println("Constructor inject nred: " + nred.getName());
    System.out.println("Constructor inject nblack: " + nblack.getName());


    MyController mc = new MyController();
    mc.setColor(new Red("No injection red"));
    System.out.println("No injection : " + mc.getColor().getName());

    return "Hello";
}
}

Цвет интерфейса:

public interface Color {
    public String getName();
}

Класс Красный:

@Component
public class Red implements Color{
private String name;

@Override
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Red(String name) {
    System.out.println("Red color: "+ name);
    this.name = name;
}

public Red() {
    System.out.println("Red color default constructor");
}

}

Класс Черный:

@Component
public class Black implements Color{
private String name;

@Override
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Black(String name) {
    System.out.println("Black color: "+ name);
    this.name = name;
}

public Black() {
    System.out.println("Black color default constructor");
}

}

Тип конфигурации для создания Beans:

@Configuration
public class Config {

@Bean(name = "configRed")
public Red getRedInstance() {
    Red red = new Red();
    red.setName("Config red");
    return red;
}

@Bean(name = "configBlack")
public Black getBlackInstance() {
    Black black = new Black();
    black.setName("config Black");
    return black;
}

@Bean(name = "constRed")
public Red getConstRedInstance() {
    Red red = new Red();
    red.setName("Config const red");
    return red;
}

@Bean(name = "constBlack")
public Black getConstBlackInstance() {
    Black black = new Black();
    black.setName("config const Black");
    return black;
}
}

BootApplication (основной класс):

@SpringBootApplication
@ComponentScan(basePackages = {"com"})
public class BootApplication {

public static void main(String[] args) {
    SpringApplication.run(BootApplication.class, args);
}
}

Запустить приложение и нажать URL-адрес: GET 127.0.0.1:8080/abc/dev/customers/

Output:
Injecting setter
Field injection red: Config red
Field injection: null
Setter injection black: config Black
Constructor inject nred: Config const red
Constructor inject nblack: config const Black
Red color: No injection red
Injecting setter
No injection : No injection red

Ответ 8

С примерами? Здесь простой:

public class TwoInjectionStyles {
    private Foo foo;

    // Constructor injection
    public TwoInjectionStyles(Foo f) {
        this.foo = f;
    }

    // Setting injection
    public void setFoo(Foo f) { this.foo = f; }
}

Лично я предпочитаю инъекцию конструктора, когда могу.

В обоих случаях bean factory создает экземпляры TwoInjectionStyles и Foo и дает прежнюю зависимость от Foo.