Difference between @Bean and @Autowired

JavaSpringDependency Injection

Java Problem Overview


Why can't I use @Autowired in this case?

@SpringBootApplication
public class Application {

	@Autowired
	BookingService bookingService;

	public static void main(String[] args) {
		bookingService.book("Alice", "Bob", "Carol");
	}
}

but can use @Bean

@SpringBootApplication
public class Application {

	@Bean
	BookingService bookingService() {
		return new BookingService();
	}

	public static void main(String[] args) {
		ApplicationContext ctx = SpringApplication.run(Application.class, args);
		BookingService bookingService = ctx.getBean(BookingService.class);
		bookingService.book("Alice", "Bob", "Carol");
	}
}

Aren't the two ways to generate BookingService the same thing?

Java Solutions


Solution 1 - Java

@Bean and @Autowired do two very different things. The other answers here explain in a little more detail, but at a simpler level:

  • @Bean tells Spring 'here is an instance of this class, please keep hold of it and give it back to me when I ask'.

  • @Autowired says 'please give me an instance of this class, for example, one that I created with an @Bean annotation earlier'.

Does that make sense? In your first example, you're asking Spring to give you an instance of BookingService, but you're never creating one, so Spring has nothing to give you. In your second example, you're creating a new instance of BookingService, telling Spring about it, and then, in the main() method, asking for it back.

If you wanted, you could remove the two additional lines from the second main() method, and combine your two examples as below:

@SpringBootApplication
public class Application {

  @Autowired
  BookingService bookingService;

  @Bean
  BookingService bookingService() {
    return new BookingService();
  }

  public static void main(String[] args) {
    bookingService.book("Alice", "Bob", "Carol");
  }
}

In this case, the @Bean annotation gives Spring the BookingService, and the @Autowired makes use of it.

This would be a slightly pointless example, as you're using it all in the same class, but it becomes useful if you have the @Bean defined in one class, and the @Autowired in a different one.

Solution 2 - Java

@Bean
BookingService bookingService() {
    return new BookingService();
}

Annotating @Bean only registers the service as a bean(kind of an Object) in the spring application context. In simple words, it is just registration and nothing else.

@Autowired
BookingService bookingService;

Annotating a variable with @Autowired injects a BookingService bean(i.e Object) from Spring Application Context.

(i.e) The registered object with @Bean annotation will be injected to the variable annotated with @Autowired.

Hope this clears your doubt!

Solution 3 - Java

great answer by @DaveyDaveDave In the example instead of

@Bean
  BookingService bookingService() {
    return new BookingService();
  }

You can use @Service annotation on BookingService class

Solution 4 - Java

Contrary to what the highest voted answer here claims, they are NOT two very different things. @Bean and @Autowired and interchangeable in most cases.

Suppose you have a @Bean method that returns an instance of a Car. You can literally get rid of that bean method and add @Component on the Car class and then autowire it.

And vice versa. Whatever class you have instantiated using @Autowired, you can instantiate it inside a class with @Configuration annotation using @Bean on the method.

Places where you will use @Bean instead of @Autowired

1>You do not have access to change the class to add @Component annotation, hence you cannot autowire it.

2>You want to customize the instantiation of the class.

For example if you are instantiating a Resilience4J Circuit breaker class, if you do it inside a method with @Bean, you have the option of setting all the config using code like this

@Bean
public CircuitBreaker fooCircuitBreaker() {
    CircuitBreakerConfig.Builder builder = CircuitBreakerConfig.custom().
            slidingWindowSize(xxx).
            failureRateThreshold(xxx).
            waitDurationInOpenState(xxx)).
            ignoreException(e -> {
                if (e instanceof HttpStatusCodeException) {
                    HttpStatusCodeException httpStatusCodeException = (HttpStatusCodeException) e;
                    if (httpStatusCodeException.getStatusCode().is4xxClientError()) {
                        return true;
                    }
                }
                return false;
            });
    circuitBreakerRegistry.addConfiguration(xxx, builder.build());
    return circuitBreakerRegistry.circuitBreaker(xxx, xxx);
}

Solution 5 - Java

Here's good article about @Autowired annotation: http://www.baeldung.com/spring-autowire

The @Autowired annotation can instantiate your injectables by defining @ComponentScan("namespace.with.your.components.for.inject") on config class

@Configuration
@ComponentScan("com.baeldung.autowire.sample")
public class AppConfig {}

All components must be marked by @Component annotation. It replaces the @Bean annotation.

Solution 6 - Java

@Bean is just for the metadata definition to create the bean(equivalent to tag). @Autowired is to inject the dependancy into a bean(equivalent to ref XML tag/attribute).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionzhuochen shenView Question on Stackoverflow
Solution 1 - JavaDaveyDaveDaveView Answer on Stackoverflow
Solution 2 - JavapmvermaView Answer on Stackoverflow
Solution 3 - JavaKris SwatView Answer on Stackoverflow
Solution 4 - Javadeveloper747View Answer on Stackoverflow
Solution 5 - Javan0rtanView Answer on Stackoverflow
Solution 6 - JavaSARIKAView Answer on Stackoverflow