Магия @ComponentScan и @Component

Я все еще изучаю внедрение весенней зависимости в глубину.

Мой первый класс — это класс конфигурации, где я объявляю контейнеру загрузку и управление bean-компонентами, объявленными в аннотированных методах.

package ioc.question_004;

import ioc.commun.Person;
import ioc.commun.Profession;
import org.springframework.context.annotation.*;

@Configuration
public class MyConfiguration {

    @Bean
    public Profession profession(){
        return Profession.builder()
                     .name("professor")
                     .description("professor in the university")
                     .build();
    }

    @Bean
    public Person person(){
        return Person.builder()
                     .name("Bagna")
                     .age(52)
                     .profession(profession())
                     .build();
    }

}

Мой второй класс - это daoRepository, он выглядит так:

package ioc.question_008.dao;

import ioc.commun.Person;
import lombok.*;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

@Repository
@Builder
@Setter
@Getter
@EqualsAndHashCode
@ToString
public class MyDaoRepository implements dao {

    List<Person> personList = new ArrayList<>();

    @Override
    public boolean save( Person person ){
        return this.personList.add(person);
    }

    @Override
    public boolean delete( Person person ){
        return  this.personList.remove(person);
    }

}

Мой рабочий код выглядит следующим образом:

@Configuration
@Import(MyConfiguration.class)
@ComponentScan(basePackageClasses = {MyDaoRepository.class} )
public class DependencyInjection {
    public static void main( String[] args ) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DependencyInjection.class);
        dao myDaoRepository = (MyDaoRepository) context.getBean("myDaoRepository");
        System.out.println(myDaoRepository);
    }

}

Волшебным образом MyDaoRepository содержит человека @Bean, объявленного в классе конфигурации MyConfiguration:

MyDaoRepository (personList = [Person (имя = Багна, возраст = 52, профессия = Профессия (имя = профессор, описание = профессор в университете))])

Я думаю, что контейнер автоматически внедрил этот объект, даже если я об этом не просил. Возможно, компилятор добавил некоторую аннотацию @Autowired. Я не уверен.

Не могли бы вы объяснить мне, как я могу попросить контейнер Spring не вводить бобы, даже если они существуют в контейнере (например, человек-боб), если только я не попрошу сделать инъекцию самостоятельно с аннотацией @Autowired.


person xmen-5    schedule 03.07.2019    source источник
comment
Что значит содержит? Список в репозитории?   -  person daniu    schedule 03.07.2019
comment
да, автоматически список содержит этот объект человека, объявленный в классе конфигурации..   -  person xmen-5    schedule 03.07.2019
comment
Вы не можете попросить Spring не внедрять зависимости bean-компонентов, если вы также укажете Spring (через сканирование компонентов) автоматически создавать сами bean-компоненты. Если вам нужно ручное управление, не сканируйте компоненты и не пишите метод @Bean самостоятельно.   -  person chrylis -cautiouslyoptimistic-    schedule 03.07.2019
comment
Может быть, я не был ясен и недвусмыслен в своем вопросе. 1- Решение, которое я хотел, состоит в том, чтобы запросить внедрение зависимостей, но не использовать bean-компонент типа person, определенный в классе конфигурации (зная, что включение этого класса конфигурации является обязательным для других экземпляров bean-компонента, и решение для удаления @Import не будет работать .) 2-Возвращаясь к моему коду, как объект человека был введен в мой список (внедрение конструктором, методом установки или внедрением поля)?   -  person xmen-5    schedule 03.07.2019


Ответы (1)


Причина в сочетании автосвязывания коллекций Spring и Builder ломбока.

Во-первых, @Builder добавляет конструктор всех аргументов MyDaoRepository(List<Person> list).

Во-вторых, Spring автоматически определяет ваши фабричные методы @Bean public Person person().

Теперь, поскольку конструктор ожидает коллекцию, Spring собирает все Person-бины, которые он может найти, в List и вводит их в конструктор, соответствующим образом настраивая список.

Я думаю (но в настоящее время это не проверено, но задокументировано здесь), что добавление @Autowired(required = false) к вашему List<Person> persons - это то, что вам нужно в этом случае, так как оно помечается как необязательное, и Spring не будет его вводить. (EDIT: я ошибся, вам все еще нужен конструктор без аргументов, чтобы это работало, но без какой-либо аннотации @Autowired список все равно не будет введен таким образом. required=false просто предотвращает исключение, когда правильный Person bean не найден. )

РЕДАКТИРОВАТЬ: Как отметил г-н Родди, Родди из Frozen Peas, также можно было бы добавить другой конструктор для spring для создания вашего bean-компонента, например. аннотируя свой репозиторий с помощью @NoArgsConstructor

person sfiss    schedule 03.07.2019
comment
Теоретически можно также добавить конструктор без аргументов для Spring: @NoArgsConstructor - person Roddy of the Frozen Peas; 03.07.2019
comment
Да, я предполагаю, что ему нужны квадриллионы аннотаций, как и в репозитории :P Но я думаю, что упомяну об этом, хорошая мысль, спасибо - person sfiss; 03.07.2019
comment
@Autowired(required = false) не работает, потому что это означает внедрение объекта, но если вы не найдете этот объект, не создавайте исключение. - person xmen-5; 03.07.2019
comment
NoArgsConstructor работает отлично, на мой взгляд, потому что в списке нет аннотации Autowired, но в конструкторе no arg. может кто-нибудь это подтвердить. - person xmen-5; 03.07.2019
comment
zak zak, компилятор (как и ломбок с настройкой по умолчанию) не добавляет аннотаций волшебным образом. Он просто не вводится, потому что Spring пытается внедрить все параметры вашего конструктора, и если у вас их нет, ничего не вводится (при условии, что внедрение поля/установщика не используется). - person sfiss; 03.07.2019
comment
Я настоятельно рекомендую не комбинировать несколько довольно сложных технологий, если это действительно необходимо. Так что лучше пока исключите Lombok и поиграйте с чистой Java и Spring. В конце концов, Lombok не добавляет никаких дополнительных функций, это просто инструмент для сохранения нескольких строк кода. А если вы используете современную IDE, вы все равно не пишете этот код, так как он генерируется за вас автоматически. - person stepio; 03.07.2019
comment
@stepio, я согласен, что нужно знать об используемых технологиях и использовать их надлежащим образом. Тем не менее, Lombok также позволяет читать меньше шаблонов (нет источника, но кто-то сказал, что вы читаете код в 10 раз чаще, чем пишете). ОП должен подумать, нужны ли все эти ломбокские аннотации (мое мнение: в этом месте они действительно плохие). - person sfiss; 03.07.2019