2
votes

I'm still learning spring dependency injection in depth.

My first class is a configuration class, where i declare to the container to load and manage the beans declared in the annotated methods.

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

}

My second class is a daoRepository, it looks likes:

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

}

My running code is as follows:

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

}

Magically MyDaoRepository contains the @Bean person declared in the configuration class MyConfiguration:

MyDaoRepository(personList=[Person(name=Bagna, age=52, profession=Profession(name=professor, description=professor in the university))])

I thnik that the container injected this object automatically even if i didn't ask for that. May be some @Autowired annotation is added by the compiler. I'm not sure.

Could you please explain to me how i can ask the spring container to not inject the beans even if they exists in the container(the bean person for example), unless i ask the to do the injection by myself with the @Autowired annotation.

1
What do you mean "contains" it? The list in the repository? - daniu
yes, automatically the list contains this person object declared in the configuration class.. - xmen-5
You can't ask Spring not to inject bean dependencies if you also tell Spring (via component scanning) to automatically create the beans itself. If you want manual control, don't component-scan and write an @Bean method yourself. - chrylis -cautiouslyoptimistic-
May be i wasn't clear and explicit in my question. 1- The solution i was willing is to ask for dependency injection but not using the bean of type person defined in the configuration class.(knowing that including this configuration class is manadatory for others bean instance and the solution to remove @Import will not work.) 2-returning to my code, how was the person object injected to my list(injection by constructor, setter method or field injection)? - xmen-5

1 Answers

7
votes

The reason is the combination of spring's autowiring of collections and lombok's Builder

First, the @Builder adds an all args constructor MyDaoRepository(List<Person> list).

Second, spring automatically detects your factory methods @Bean public Person person().

Now, since the constructor expects a collection, spring accumulates all Person-beans it can find into a List and injects it into the constructor, setting the list accordingly.

I think (but it is currently untested but documented here), that adding @Autowired(required = false) to your List<Person> persons property is what you want in this case, as that marks it as optional and spring will not inject it. (EDIT: I was mistaken, you still need the no-args-constructor for this to work, but without any @Autowired annotation the list would not get injected that way anyway. The required=false simply prevents the exception when no proper Person bean is found.)

EDIT: As Mr. Roddy, the Roddy of the Frozen Peas, pointed out, it would also be possible to add a different constructor for spring to create your bean, e.g. by annotating your repository with @NoArgsConstructor