3

I have learnt that autowiring a bean is actually not a good practice. This is also mentioned in the spring document. I know that there are two types of bean configuration. One is by XML config, another is by java configuration class. If we want to use code to do bean configuration and not using @autowired, how can we do that? It seems like if using code, we will still need @autowired in order to inject the bean?

e.g. in the following, if we want to not using @Autowired, how can we do that? and what should be the best practice?

@Service
public class ClassA {
  private ClassB classB;

  @Autowired
  public ClassA(ClassB classB) {
    this.classB = classB;
  }
}
once
  • 536
  • 7
  • 21
  • You can just remove the `@Autowired` annotation from the constructor and it will still work (if you're not using a really old version of Spring). – Jesper Sep 23 '19 at 14:23
  • I recommend the following article: https://www.endoflineblog.com/spring-best-practices. Anyway I keep using `@Autowired` anywhere :) – abanet Aug 04 '21 at 12:20

3 Answers3

12

Where have you read that autowiring is bad practice? Autowiring is automatic dependency injection - the core function of Spring.

I think you've read that field injection like this is bad practice because it for instance makes mocking out dependencies for testing impossible:

@Service
public class ClassA {
  @Autowired
  private ClassB classB;

}

In newer Spring versions you can omit the @Autowired annotation on the constructor if the class only have one constructor.

msfoster
  • 2,474
  • 1
  • 17
  • 19
  • I like to do it like this and then in my tests use the `ReflectionTestUtils` to mock those autowired properties. For me it makes the code more readable. – Paplusc Sep 23 '19 at 14:31
  • 2
    Your code becomes useless when you decide to not use Spring anymore, or use a different dependency injection framework. Using reflection to stub dependencies is not needed if you follow common best practice patterns. I suggest you re-evalute how you are doing things. It's just as easy to use Mockito for stubbing. – msfoster Sep 23 '19 at 14:35
  • @Paplusc If you want to write as little as possible, you could have a look at Lombok and `@RequiredArgsConstructor` – msfoster Sep 23 '19 at 14:36
  • As supplement, I read from the book Pro Spring 5 that using autowiring in many cases lead to bad practices and is inflexible in large applications. However, in real life, in most cases I see the use of autowiring, either by setter or constructor injection, and I have never seen any real applications built using pure xml bean configuration. So I'm puzzled by the use of it after reading about that. – once Jan 11 '21 at 11:52
  • I read that: "One crucial mistake that I see a lot of people making is structuring their business logic classes in a way that makes them depend on Spring. A common way to introduce that sort of dependency is by using annotations like '@Component', '@Autowired', '@Service', etc." in the interesting blog https://www.endoflineblog.com/spring-best-practices but I keep using @Autowired everywhere because I don't think I'm going to change my dependency injection container and... it is so convenient to use... – abanet Aug 04 '21 at 12:14
5

It is better to use a constructor dependency injection if possible because constructor injection prevents you from circular dependencies.

@Service
// @RequiredArgsConstructor // if using lombok
public class ClassA {
     private ClassB classB;

     // If not using lombok
     public ClassA(ClassB classB) {
          this.classB = classB;
     }
}

However, setter injection works as well. Look at more answers here.

Alan Sereb
  • 2,358
  • 2
  • 17
  • 31
  • 1
    Yea, these days I just try to avoid using field dependency injection and put the DI into constructor, that make the testing easier. – Eric Tan Oct 08 '20 at 12:26
2

One option would be to use a @Configuration class with @Bean methods within. Something like this.

@Configuration 
public MyConfigClass {

    @Bean
    ClassB makeClassB(){
        return new ClassB();
    }

    @Bean
    ClassA makeClassA(final ClassB classB){
        return new ClassA(classB);
    }
}

Please be aware that if a @Component class has a single constructor it is, by default, annotated with @Autowired. This may help to explain why it sometimes seems to work but you cannot see any injection.

Pete
  • 205
  • 2
  • 14
  • This is basically the exact same thing as dependency injection by constructor - Spring provides the method `makeClassA` with an instance of `ClassB`. – msfoster Sep 23 '19 at 14:26